from utils import utils
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk

class RuneSheet(tk.Frame):
	def __init__(self, parent: tk.Widget, rune_list: list, categories_size=65, categories_space=20, keystone_size=80, rune_size=60, small_rune_size=50, horizontal_space=5, vertical_space=15, *args, **kwargs) -> None:
		tk.Frame.__init__(self, parent, *args, **kwargs)
		self.categories_space = categories_space
		self.previous_active = [-1, -1]
		self['bg'] = utils.widget_color
		self.bg_label = tk.Label(self, bg=utils.widget_color)
		self.main_categories = RuneHeaderFrame(self, rune_list=rune_list[0], size=categories_size, horizontal_space=horizontal_space, background=utils.widget_color)
		self.secondary_categories = RuneHeaderFrame(self, rune_list=rune_list[0], size=categories_size, horizontal_space=horizontal_space, background=utils.widget_color)
		self.pages = [RuneFrame(self, page, keystone_size=keystone_size, rune_size=rune_size, horizontal_space=horizontal_space, is_primary=True, vertical_space=vertical_space, background=utils.widget_color) for page in rune_list[1:-1]]
		self.small_runes = StatRunes(self, rune_list=rune_list[-1], rune_size=small_rune_size, horizontal_space=15, background=utils.widget_color)
		self.width = self.main_categories.width + self.secondary_categories.width - self.secondary_categories.size + self.categories_space * 3
		self.height = self.secondary_categories.size + self.pages[0].height - keystone_size + self.small_runes.height + categories_space * 1

	def place(self, x=0, y=0):
		super().place(x=x, y=y, width=self.width, height=self.height)
		# self.bg_label.place(x=0, y=0, width=self.width, height=self.height)

	def place_forget(self):
		super().place_forget()
		self.main_categories.place_forget()
		self.secondary_categories.place_forget()
		for page in self.pages:
			page.place_forget()
		self.small_runes.place_forget()

	def clear_pages(self):
		if self.previous_active[0] >= 0:
			self.pages[self.previous_active[0]].place_forget()
		if self.previous_active[1] >= 0:
			self.pages[self.previous_active[1]].place_forget()

	def select_main_page(self, index: int):
		page = self.pages[index]
		page.is_primary = True
		page.place(self.main_categories.width / 2 - page.width/2 + self.categories_space, self.main_categories.size + self.categories_space*2)
		self.previous_active[0] = index

	def select_secondary_page(self, runes):
		page = self.pages[runes[0]]
		page.select_runes(runes[1:])
		page.is_primary = False
		page.place((self.secondary_categories.width - page.width) / 2 + self.main_categories.width + 2*self.categories_space, self.secondary_categories.size + self.categories_space*2)
		self.previous_active[1] = runes[0]

	def select_small_runes(self, runes):
		self.small_runes.select_runes(runes)
		self.small_runes.place_forget()
		self.small_runes.place(x=self.main_categories.width + 2 * self.categories_space + (self.secondary_categories.width - self.small_runes.width)/2, y=self.secondary_categories.size + self.pages[self.previous_active[1]].height + 2 * self.categories_space)

	def select_runes(self, main_runes, second_runes, small_runes):
		self.main_categories.place_forget()
		self.main_categories.place(x=self.categories_space, y=self.categories_space)
		self.pages[self.previous_active[0]].place_forget()
		self.pages[self.previous_active[1]].place_forget()

		self.main_categories.set_active(main_runes[0])
		self.pages[main_runes[0]].select_runes(main_runes[1:])
		self.select_main_page(main_runes[0])

		self.secondary_categories.set_hidden(main_runes[0])
		self.secondary_categories.set_active(second_runes[0])
		self.secondary_categories.place_forget()
		self.secondary_categories.place(x=self.main_categories.width + 2*self.categories_space, y=self.categories_space)

		self.select_secondary_page(second_runes)
		self.select_small_runes(small_runes)

class RuneHeaderFrame(tk.Frame):
	def __init__(self, parent, rune_list: list, size: float, horizontal_space, is_primary: bool = False, *args, **kwargs) -> None:
		tk.Frame.__init__(self, parent, *args, **kwargs)
		self.length = len(rune_list)
		self.button_list = []
		self.last_active = 0
		self.size = size
		self.hidden_category = -1
		self.is_primary = is_primary
		self.horizontal_space = horizontal_space
		self.width = self.length * (size + horizontal_space)
		self.button_list = [RuneButton(parent=self, icon=rune, size=self.size, bg=self['bg']) for rune in rune_list]

	def set_active(self, index):
		self.button_list[self.last_active].set_active(False)
		self.button_list[index].set_active(True)
		self.last_active = index

	def set_hidden(self, index: int):
		self.hidden_category = index
		self.width = self.length * (self.size + self.horizontal_space) - self.size

	def place(self, x=0, y=0):
		super().place(x=x, y=y, width=self.width, height=self.size + self.horizontal_space)

		x = (self.width - (self.size + self.horizontal_space) * (self.length - (self.hidden_category != -1)) - self.horizontal_space/2) / 2
		for b, category_button in enumerate(self.button_list):
			if b != self.hidden_category:
				category_button.place(x=x, y=0, height=self.size, width=self.size)
				x += self.size + self.horizontal_space

	def place_forget(self) -> None:
		super().place_forget()
		for button in self.button_list:
			button.place_forget()

class StatRunes(tk.Frame):
	def __init__(self, parent, rune_list, rune_size=40, horizontal_space=5, vertical_space=5, *args, **kwargs) -> None:
		tk.Frame.__init__(self, parent, *args, **kwargs)
		self.rune_size = rune_size
		self.previous_selected = [-1, -1, -1]
		self.horizontal_space = horizontal_space
		self.vertical_space = vertical_space
		self.height = (self.rune_size + self.vertical_space) * len(rune_list)
		rune_num = max((len(row) for row in rune_list))
		self.width = rune_num * self.rune_size + (rune_num + 1) * self.horizontal_space
		self.rune_buttons = [[RuneButton(parent=self, icon=rune, size=self.rune_size, bg=utils.widget_color) for rune in row] for row in rune_list]

	def select_runes(self, runes):
		for i, value in enumerate(self.previous_selected):
			if value != -1:
				self.rune_buttons[i][value].set_active(False)
		for i in range(len(runes)):
			self.rune_buttons[i][runes[i]].set_active(True)
		self.previous_selected = runes

	def place(self, x: float = 0, y: float = 0):
		super().place(x=x, y=y, width=self.width, height=self.height)

		y = 0
		for row in self.rune_buttons:
			x = (self.width - len(row) * (self.rune_size + self.horizontal_space) + self.horizontal_space) / 2
			for b in row:
				b.place(x=x, y=y, height=self.rune_size, width=self.rune_size)
				x += self.rune_size + self.horizontal_space

			y += self.vertical_space + self.rune_size

	def place_forget(self) -> None:
		super().place_forget()
		for row in self.rune_buttons:
			for button in row:
				button.place_forget()

class RuneFrame(tk.Frame):
	def __init__(self, parent, rune_list, is_primary: bool = True, keystone_size=64, rune_size=64, horizontal_space=5, vertical_space=5, *args, **kwargs) -> None:
		tk.Frame.__init__(self, parent, *args, **kwargs)
		self.rune_buttons = []
		self.is_primary = is_primary
		self.previous_active = [0 for _ in rune_list]
		self.row_sizes = [len(row) for row in rune_list]
		self.length = [max((row for row in self.row_sizes[not self.is_primary:])), max((row for row in self.row_sizes))]
		self.rune_sizes = [rune_size, keystone_size]
		self.horizontal_space = horizontal_space
		self.vertical_space = vertical_space
		self.rune_buttons = [[RuneButton(parent=self, icon=rune, size=keystone_size, bg=self['bg']) for rune in rune_list[0]]] + [[RuneButton(parent=self, icon=rune, size=rune_size, borderwidth=0, bg=self['bg']) for rune in row] for row in rune_list[1:]]

	@property
	def width(self) -> float:
		return self.length[self.is_primary] * (self.rune_sizes[self.is_primary] + self.horizontal_space) + self.horizontal_space

	@property
	def height(self) -> float:
		return len(self.rune_buttons[1:]) * self.rune_sizes[0] + (len(self.rune_buttons) + self.is_primary) * self.vertical_space/((not self.is_primary) + 1) + self.rune_sizes[1] * self.is_primary

	def select_runes(self, runes: list) -> None:
		for i, row in zip(self.previous_active, self.rune_buttons):
			row[i].set_active(False)
		for i in range(len(runes)):
			if runes[i] != -1:
				self.rune_buttons[i][runes[i]].set_active(True)
		self.previous_active = runes

	def place(self, x: float = 0, y: float = 0) -> None:
		super().place(x=x, y=y, width=self.width, height=self.height)

		y = 0
		for row in self.rune_buttons[not self.is_primary:]:
			size = self.rune_sizes[self.is_primary and y == 0]

			x = (self.width - len(row) * (size + self.horizontal_space) + self.horizontal_space) / 2
			for b in row:
				b.place(x=x, y=y, height=size, width=size)
				x += size + self.horizontal_space
			y += self.vertical_space / ((not self.is_primary) + 1) + size

	def place_forget(self) -> None:
		super().place_forget()
		for row in self.rune_buttons:
			for button in row:
				button.place_forget()

class RuneButton(tk.Button):
	def __init__(self, parent: tk.Widget, icon, size: float, *args, **kwargs):
		tk.Button.__init__(self, parent, *args, **kwargs)
		icon = Image.open(icon).resize((int(size), int(size)))
		self['borderwidth'] = 0
		self.active = False
		self.active_image = ImageTk.PhotoImage(icon)
		self.inactive_image = ImageTk.PhotoImage(utils.grayscale(icon))
		self['activebackground'] = self['bg']
		self.set_active(False)
		# self.bind("<Button-1>", lambda _ : "break", add=True)

	def set_active(self, status: bool) -> None:
		if status:
			self['image'] = self.active_image
		else:
			self['image'] = self.inactive_image
		self.active = status


from django.shortcuts import render,redirect

from .models import JobApplication
from .models import JobListing

def index(request):
    return render(request, 'index.html')

def job_listings(request):
    job_listings = JobListing.objects.all()
    context = {
        'job_listings': job_listings
    }
    return render(request, 'job_listings.html', context)

def apply_job(request, job_id):
    if request.method == 'POST':
        name = request.POST['name']
        email = request.POST['email']
        resume = request.FILES['resume']
        cover_letter = request.POST['cover_letter']

        # Create a new JobApplication object and save it to the database
        job_application = JobApplication.objects.create(
            job_id=job_id,
            name=name,
            email=email,
            resume=resume,
            cover_letter=cover_letter
        )

        # After saving, you can redirect the user to a success page or back to the job listings
        return redirect('job_listings')

    # Get the job details based on job_id (you need to implement this)
    # job = JobListing.objects.get(id=job_id)

    context = {
        # Pass the job details to the template
        # 'job': job,
    }
    return render(request, 'apply_job.html', context)


import sympy as sp
from Physics.Vector import Vector
class VectorField:
    def __init__(self, function_label, component_equation_texts):
        self.function_label = function_label
        self.components = []
        for component_equation_text in component_equation_texts:
            self.components.append(sp.parse_expr(component_equation_text))

    def solve(self, *args):
        new_components = self.components.copy()
        for substitution in args:
            var, value = substitution.split("=")
            for i in range(len(new_components)):
                try:
                    new_components[i] = new_components[i].subs(var, value)
                except:
                    raise Exception
        valid = True
        for component in new_components:
            if(not isinstance(component,sp.core.numbers.Integer) and not isinstance(component,sp.core.numbers.Float)):
                valid = False
        if(valid):
            for i in range(len(new_components)):
                if(isinstance(new_components[i], sp.core.numbers.Integer)):
                    new_components[i] = int(new_components[i])
                elif(isinstance(new_components[i], sp.core.numbers.Float)):
                    new_components[i] = float(new_components[i])
            return Vector(len(self.components),new_components)
        else:
            #CHANGE THIS FUNCTION LABEL TO FIT NEW VARIABLES
            new_text_components = []
            for component in new_components:
                new_text_components.append(str(component))
            return VectorField(self.function_label, new_text_components)

    def __str__(self):
        text = self.function_label + " = <"

        for component in self.components:
            text = text + str(component) + ","

        text = text[0 : len(text)-1]
        text = text + ">"

        return text


import sys
from colorama import Style, init, Fore
import config
import time
import os
if os.name == 'nt':
    import msvcrt

else:
    import select
    import termios
    import sys

def printLaberinto(laberinto):

    if config.safegraphic:
        print()
        for linea in laberinto:
            for valor in linea:
                if valor==0:
                    print(" " ,end=" ")
                elif valor==9:
                    print(Fore.LIGHTRED_EX+"â–ˆâ–ˆ",end="")
                elif valor==8:
                    print(Fore.CYAN+"O ",end="")
                elif valor==7:
                    print(Fore.YELLOW+"â–ˆâ–ˆ",end="")
                else :
                    print(Fore.RESET+str(valor)+" ",end="")
            print()
        print(Fore.RESET)
    else:
        for linea in laberinto:
            for valor in linea:
                if valor==0:
                    print(" " ,end=" ")
                elif valor==9:
                    print("ðŸŸ«",end="")
                elif valor==8:
                    print("ðŸ¤–",end="")
                elif valor==7:
                    print("ðŸš©",end="")
                else :
                    print("ðŸ’²",end="")
            print()

def mostrarsolucion(solucion):
    for estadoMostrar in solucion:
        print(Fore.GREEN + estadoMostrar.movimientoRealizado)
    print(Fore.WHITE+"")
    #IASI.printLaberinto(estadoMostrar.tablero)
    print("")

def mostrassoluciongrafica(solucion):
    for estadoMostrar in solucion:
        os.system('cls' if os.name == 'nt' else 'clear')
        printLaberinto(estadoMostrar.tablero)
        time.sleep(0.5)

def movimiento(node, parent):
    if node.x < parent.x and node.y < parent.y:
        return 'Izquierda Arriba'
    elif node.x < parent.x and node.y > parent.y:
        return 'Derecha Arriba'
    elif node.x > parent.x and node.y < parent.y:
        return 'Izquierda Abajo '
    elif node.x > parent.x and node.y > parent.y:
        return 'Derecha Abajo'
    elif node.x < parent.x:
        return 'Arriba'
    elif node.x > parent.x:
        return 'Abajo'
    elif node.y < parent.y:
        return 'Iquierda'
    elif node.y > parent.y:
        return 'Derecha'

#Localizar la posicion de la meta
def localizarmeta(laberinto):
    fila=0
    for linea in laberinto:
        columna=0
        for valor in linea:
            if valor==7:
                return fila, columna
            columna=columna+1
        fila=fila+1

#Localiza la posicion del robot
def locateBot(laberinto):
    for i, linea in enumerate(laberinto):
        for j, valor in enumerate(linea):
            if valor == 8:
                return i, j
    return -1,-1

def lectura_fichero(nom_fichero):
    # Abrir el archivo con nombre especificado en el parÃ¡metro "nom_fichero" en modo lectura ('r')
    with open(nom_fichero, 'r') as fichero:
        # Leer la primera lÃnea del archivo, convertirla a entero y almacenarlo en la variable "n"
        n = int(fichero.readline().strip())
        # Inicializar una matriz vacÃa "laberinto"
        laberinto = []
        # Procesar el archivo lÃnea por lÃnea
        for line in fichero:
            # Inicializar una lista vacÃa "linea"
            linea = []
            # Procesar cada valor en la lÃnea actual y agregarlo a la lista "linea" como un entero
            for value in line.strip().split(','):
                try:
                    linea.append(int(value))
                except ValueError:
                    # Si el valor no puede ser convertido a entero, se omite
                    pass
            # Agregar la lista "linea" al final de la matriz "laberinto"
            if linea:
                laberinto.append(linea)
        #Cierre del fichero
        fichero.close()
        # Retornar los valores de "n" y "laberinto"

        return n, laberinto

def mostrassoluciongraficaALT(solucion, movsR):
    for estadoMostrar in reversed(solucion):
        os.system('cls' if os.name == 'nt' else 'clear')
        printLaberinto(estadoMostrar.tablero)
        movsR.put(estadoMostrar.movimientoRealizado)
        time.sleep(0.5)

def mostrarsolucionALT(solucion):
    for estadoMostrar in reversed(solucion):
        print(Fore.GREEN + estadoMostrar.movimientoRealizado)
    print(Fore.WHITE+"")
    #IASI.printLaberinto(estadoMostrar.tablero)
    print("")
def sumamonedas(tablero):
    suma = 0
    for fila in tablero:
        for valor in fila:
            if valor >= 1 and valor <= 6:
                suma += valor
    return suma

def flushInputs():

    if os.name == 'nt':
        while(msvcrt.kbhit()):
            msvcrt.getch()

    else:
        # VacÃa el buffer de entrada de sys.stdin
        termios.tcflush(sys.stdin, termios.TCIFLUSH)


import matplotlib.pyplot as plt
import numpy as np

# Plotting the output control variable (High (-))
def output_controller_high_negative(x):
    if -0.09 >= x >= -0.15:
        return_value = 1
    elif -0.03 >= x >= -0.09:
        return_value = -(100 / 6) * x - 0.5
    else:
        return_value = 0
    return return_value

# Plotting the output control variable (Small (-))
def output_controller_small_negative(x):
    if 0 >= x >= -0.03:
        return_value = -(100 / 3) * x
    elif -0.03 >= x >= -0.06:
        return_value = (100 / 3) * x + 2
    else:
        return_value = 0
    return return_value

# Plotting the output control variable (Good)
def output_controller_good(x):
    if 0 >= x >= -0.03:
        return_value = (100 / 3) * x + 1
    elif 0.03 >= x >= 0:
        return_value = - (100 / 3) * x + 1
    else:
        return_value = 0
    return return_value

# Plotting the output control variable (Small (+))
def output_controller_small_positive(x):
    if 0.06 >= x >= 0.03:
        return_value = - (100 / 3) * x + 2
    elif 0.03 >= x >= 0:
        return_value = (100 / 3) * x
    else:
        return_value = 0
    return return_value

# Plotting the output control variable (High (+))
def output_controller_high_positive(x):
    if 0.15 >= x >= 0.09:
        return_value = 1
    elif 0.09 >= x >= 0.03:
        return_value = (100 / 6) * x - 0.5
    else:
        return_value = 0
    return return_value

# Define x-axis for the output control value
t = np.linspace(-0.15, 0.15, 400)
counter = 0
high_negative = np.zeros(shape=t.shape)
small_negative = np.zeros(shape=t.shape)
good = np.zeros(shape=t.shape)
small_positive = np.zeros(shape=t.shape)
high_positive = np.zeros(shape=t.shape)

for i in t:
    high_negative[counter] = output_controller_high_negative(i)
    small_negative[counter] = output_controller_small_negative(i)
    good[counter] = output_controller_good(i)
    small_positive[counter] = output_controller_small_positive(i)
    high_positive[counter] = output_controller_high_positive(i)

    counter += 1

plt.ylabel("Membership")
plt.xlabel("$\delta$")
plt.title('Fuzzy Partition for the control variable')
plt.plot(t, high_negative, label='High Infection rate (-)')
plt.plot(t, small_negative, label='Low Infection rate (-)')
plt.plot(t, good, label='Good Infection rate')
plt.plot(t, small_positive, label='Low Infection rate (+)')
plt.plot(t, high_positive, label='High Infection rate (+)')

plt.legend(bbox_to_anchor=(0.98, 1), loc="upper left")

plt.show()

# Calculating the membership for the infected bots rate (High)
def controller_high(x):
    if x >= 0.8:
        return 1
    elif x <= 0.6:
        return 0
    else:
        value = 5 * x - 3
        return value

# Calculating the membership for the infected bots rate (Good)
def controller_good(x):
    if 0.65 >= x >= 0.6:
        return_value = -20 * x + 13
    elif 0.6 >= x >= 0.55:
        return_value = (20 * x) - 11
    else:
        return_value = 0
    return return_value

# Calculating the membership for the infected bots rate (Low)
def controller_small(x):
    if x <= 0.4:
        return 1
    elif x >= 0.6:
        return 0
    else:
        value = -5 * x + 3
        return value

# Define x-axis for the infected bots rate
k = np.linspace(-0.05, 1, 400)

counter = 0
good_triangle = np.zeros(shape=k.shape)
high_triangle = np.zeros(shape=k.shape)
small_triangle = np.zeros(shape=k.shape)
for x in k:
    good_triangle[counter] = controller_good(x)
    high_triangle[counter] = controller_high(x)
    small_triangle[counter] = controller_small(x)
    counter += 1

plt.ylabel("Membership")
plt.xlabel("$\pi$")
plt.title('Fuzzy partition of the current percentage of the infected bots')
plt.plot(k, small_triangle, label='Low Infection rate')
plt.plot(k, good_triangle, label='Good Infection rate')
plt.plot(k, high_triangle, label='High Infection rate')
plt.xticks(np.arange(0, 1.1, 0.1))
plt.legend(bbox_to_anchor=(0.98, 1), loc="upper left")

plt.show()

# Calculating the membership for the effective infection rate(High)
def effective_controller_high(x):
    if 1 >= x >= 0.2:
        return 1
    elif 0 <= x <= 0.2:
        value = 5 * x
        return value
    else:
        return 0

# Calculating the membership for the effective infection rate(Good)
def effective_controller_good(x):
    if 0 >= x >= -0.2:
        return_value = 5 * x + 1
    elif 0.2 >= x >= 0:
        return_value = -5 * x + 1
    else:
        return_value = 0
    return return_value

# Calculating the membership for the effective infection rate(Small)
def effective_controller_small(x):
    if -0.2 >= x >= -1:
        return 1
    elif 0 >= x >= -0.2:
        value = -5 * x
        return value
    else:
        return 0

# Define x-axis for the current effective infection rate
m = np.linspace(-1, 1, 1000)

counter = 0
good_triangle = np.zeros(shape=m.shape)
high_triangle = np.zeros(shape=m.shape)
small_triangle = np.zeros(shape=m.shape)

for x in m:
    good_triangle[counter] = effective_controller_good(x)
    high_triangle[counter] = effective_controller_high(x)
    small_triangle[counter] = effective_controller_small(x)
    counter += 1

plt.ylabel("Membership")
plt.xlabel("$\dot\pi$")
plt.title('Fuzzy partition of the current effective infection')
plt.plot(m, small_triangle, label='Low Infection rate')
plt.plot(m, good_triangle, label='Good Infection rate')
plt.plot(m, high_triangle, label='High Infection rate')
plt.xticks(np.arange(-1, 1.1, 0.2))
plt.legend(bbox_to_anchor=(0.98, 1), loc="upper left")

plt.show()


from bs4 import BeautifulSoup
import os

# List of top dailies
dailylist = os.listdir('../topdaily/')

articles = set()

# Iterate
for file in dailylist:

    # Open top daily files
    with open('../topdaily/' + file, 'r') as f:
        soup = BeautifulSoup(f.read(), 'html.parser')

    # Pull block with article link
    blocks = soup.findAll('div', {'class': 'block block--inset block--list block--preview cardChromeless js-block js-trackedPost postItem js-postItem'})

    # Get link from aforementioned block
    # Only if they have more than 200 recommends
    links = [block.find('a', {'class': 'link link--darken'})['href'].split('?source')[0] for block in blocks if 'K' in block.find('button', {'data-action': 'show-recommends'}).get_text() or int(block.find('button', {'data-action': 'show-recommends'}).get_text().strip('K')) > 200]

    # Add link to set
    articles.update(links)

# Print set to a list of articles
with open('../articleList.txt', 'wb') as articleList:
    articleList.write('\n'.join(articles))


from functools import reduce
from operator import mul

import torch
import torch.nn as nn

class MetaModelUtils:

    AVAIL_MODULES = [nn.Linear, nn.Conv2d, nn.BatchNorm2d]

    @staticmethod
    def reset(model):
        """ Breaks history of params. """
        for module in model.modules():
            if module.__class__ in MetaModelUtils.AVAIL_MODULES:
                module.weight = nn.Parameter(module.weight.data)
                if module.bias is not None:
                    module.bias = nn.Parameter(module.bias.data)

    @staticmethod
    def get_flat_params(model):
        params = []
        for module in model.modules():
            if module.__class__ in MetaModelUtils.AVAIL_MODULES:
                params.append(module.weight.view(-1))
                if module.bias is not None:
                    params.append(module.bias.view(-1))
        return torch.cat(params)

    @staticmethod
    def set_flat_params(model, flat_params):
        offs = 0
        for i, module in enumerate(model.modules()):
            if module.__class__ in MetaModelUtils.AVAIL_MODULES:
                for k in module._parameters.keys():
                    assert k in ['weight', 'bias']
                    p = module._parameters[k]
                    if p is not None:
                        p_shape = module._parameters[k].size()
                        p_flat_shape = reduce(mul, p_shape, 1)
                        module._parameters[k] = \
                            flat_params[offs:offs+p_flat_shape].view(*p_shape)
                        offs += p_flat_shape

    @staticmethod
    def get_flat_grads(model_with_grads):
        grads = []
        for module in model_with_grads.modules():
            if module.__class__ in MetaModelUtils.AVAIL_MODULES:
                grads.append(module.weight.grad.view(-1, 1))
                if module.bias is not None:
                    grads.append(module.bias.grad.view(-1, 1))
        return torch.cat(grads)


import os, sys
import argparse
import pandas as pd

import openai

import json

def retrieve_api_key_file(api_key_file):
    with open(api_key_file) as f:
        json_key = json.load(f)

    return json_key["key"]

def get_response_from_llm(text):
    response = openai.Completion.create(
        model="text-davinci-002",
        prompt=text,
        temperature=0.7,
        max_tokens=256,
        top_p=1,
        frequency_penalty=0,
        presence_penalty=0
    )

    answer = response["choices"][0]["text"]

    if answer.strip().lower().startswith("true"):
        return True
    else:
        return False

def compose_question(col1, col2):
    text = "Q: There is a clear correlation between " + col1 + " and " + col2 + ", True or False?\n\n A:"
    return text

def output_correlated_attributes(correlated_col_pairs, output_dir):
    output_file_name = os.path.join(output_dir, "correlated_attrs")

    with open(output_file_name, "w") as f:
        for col_pair in correlated_col_pairs:
            f.write(col_pair[0] + "," + col_pair[1] + "\n")

        f.close()

def check_correlations_between_attributes(column_names):

    correlated_col_pairs = []

    for idx1 in range(len(column_names)):
        for idx2 in range(len(column_names)):
            if idx1 < idx2:
                col1 = column_names[idx1]
                col2 = column_names[idx2]

                text = compose_question(col1, col2)
                correlated_count = 0
                for k in range(6):
                    correlated = get_response_from_llm(text)
                    if correlated:
                        correlated_count += 1
                if correlated_count >= 2:
                    print("correlated attributes::", col1, col2)
                    correlated_col_pairs.append((col1, col2))

    return correlated_col_pairs

def obtain_all_attributes(data_dir):
    sample_file = os.path.join(data_dir, "train/2092/episode1_timeseries.csv")
    sample_df = pd.read_csv(sample_file)

    column_names = sample_df.columns[1:]

    return column_names

def parse_args():
    parser = argparse.ArgumentParser(description='MMDetection webcam demo')
    # parser.add_argument('config', help='test config file path')
    # parser.add_argument('checkpoint', help='checkpoint file')
    parser.add_argument('--data_dir', help='input folder')
    parser.add_argument('--api_key_file', help='input folder')
    parser.add_argument('--output', help='output folder')
    # parser.add_argument(
    #     '--device', type=str, default='cuda:0', help='CPU/CUDA device option')
    # parser.add_argument(
    #     '--show', type=bool, default=False, help='display option')
    # parser.add_argument(
    #     '--wait', type=int, default=0, help='cv2 wait time')
    args = parser.parse_args()
    return args

def main():
    args = parse_args()

    api_key = retrieve_api_key_file(args.api_key_file)

    openai.api_key = api_key

    column_names = obtain_all_attributes(args.data_dir)

    correlated_col_pairs = check_correlations_between_attributes(column_names)

    output_correlated_attributes(correlated_col_pairs, args.output)

if __name__ == '__main__':
    main()


from typing import Any, Dict, Tuple
from datetime import datetime, timezone
from uuid import uuid4
from monitor.logs.formatter import pformat
from monitor.models.state import StateModel

class ICB(StateModel):
    """
    This model is initialized to a default state but populated after sensorframe state is modified
    """
    STORAGE_RESOLUTION = 1                                          # resolution of float values stored in this model
    CONVERSION_RESOLUTION = 2                                       # resolution of int/float conversions
    OPERATING_TEMPERATURE: Tuple[float, float] = (-40.0, 100.0)     # Reasonable operating temp
    OP_RANGE: Tuple[float, float] = (0.1, 21.0)                     # O2 min, max setpoint
    CP_RANGE: Tuple[float, float] = (0.1, 21.0)                     # CO2 min, max setpoint
    TP_RANGE: Tuple[float, float] = (25.0, 40.0)                    # Temperature min, max setpoint
    TP_DEFAULT: float = 37.5                                        # Default temperature setpoint
    OP_DEFAULT: float = 20.9                                        # Default o2 setpoint
    CP_DEFAULT: float = 5.0                                         # Default co2 setpoint
    FP_DEFAULT: int = 20                                            # Default fan speed duty
    HP_DEFAULT: int = 10                                            # Default heater duty

    def __init__(self) -> None:
        super().__init__(
            _id='',
            filename='icb.json'
        )
        self._tc_set = False
        self._rh_set = False
        self._oc_set = False
        self._cc_set = False
        self._tp_set = False
        self._to_set = False
        self._cp_set = False
        self._op_set = False
        self._hp_set = False
        self._fp_set = False
        self._fc_set = False
        self._ctr_set = False
        self._tm_set = False
        self._cm_set = False
        self._om_set = False
        self._iv_set = False
        self._ct_set = False
        self._timestamp_set = False

    def __repr__(self) -> str:
        return "ICB: {}".format(pformat(self.serialize()))

    def serialize(self) -> Dict[str, Any]:
        """
        Serialize object into json compatible dict

        :return: object attributes and values
        :rtype: Dict[str, Any]
        """
        return {
            'id': self.id,
            'TC': self.tc,
            'CC': self.cc,
            'OC': self.oc,
            'RH': self.rh,
            'TP': self.tp,
            'CP': self.cp,
            'OP': self.op,
            'TO': self.to,
            'CT': self.ct,
            'CTR': self.ctr,
            'TM': self.tm,
            'FP': self.fp,
            'FC': self.fc,
            'HP': self.hp,
            'CM': self.cm,
            'OM': self.om,
            'IV': self.iv,
            'timestamp': self.timestamp,
        }

    def deserialize(self, **kwargs) -> None:
        """
        Iteratively set object properties
        """
        for k, v in kwargs.items():
            setattr(self, k, v)

    @property
    def initialized(self) -> bool:
        """
        Check if all properties have been initialized successfully

        :return: sensorframe init status
        :rtype: bool
        """
        return all(
            [
                self._tc_set,
                self._rh_set,
                self._oc_set,
                self._cc_set,
                self._tp_set,
                self._to_set,
                self._cp_set,
                self._op_set,
                self._hp_set,
                self._fp_set,
                self._fc_set,
                self._ctr_set,
                self._tm_set,
                self._cm_set,
                self._om_set,
                self._iv_set,
                self._ct_set,
                self._timestamp_set,
            ]
        )

    @property
    def tc(self) -> float:
        """
        Get current temperature (°C) @ storage resolution

        :return: temperature in °C
        :rtype: float
        """
        return self.__tc

    @tc.setter
    def tc(self, value: float) -> None:
        """
        Set current temperature (°C) @ storage resolution

        :param value: temperature in °C
        :type value: float
        """
        candidate = round(value, self.STORAGE_RESOLUTION)
        # range validation
        if self.OPERATING_TEMPERATURE[0] <= candidate <= self.OPERATING_TEMPERATURE[1]:
            self.__tc = candidate
            self._tc_set = True

    @property
    def rh(self) -> float:
        """
        Get current relative humidity concentration (%) @ storage resolution

        :return: current relative humidity concentration in %
        :rtype: float
        """
        return self.__rh

    @rh.setter
    def rh(self, value: float) -> None:
        """
        Set current relative humidity concentration (%) @ storage resolution

        :param value: current relative humidity concentration in %
        :type value: float
        """
        candidate = round(value, self.STORAGE_RESOLUTION)
        # range validation
        if 0.0 <= candidate <= 100.0:
            self.__rh = candidate
            self._rh_set = True

    @property
    def oc(self) -> float:
        """
        Set current o2 concentration (%) @ storage resolution

        :return: current o2 concentration in %
        :rtype: float
        """
        return self.__oc

    @oc.setter
    def oc(self, value: float) -> None:
        """
        Set current o2 concentration (%) @ storage resolution

        :param value: current o2 concentration in %
        :type value: float
        """
        candidate = round(value, self.STORAGE_RESOLUTION)
        # range validation
        if 0.0 <= candidate <= 100.0:
            self.__oc = candidate
            self._oc_set = True

    @property
    def cc(self) -> float:
        """
        Get current co2 concentration (%) @ storage resolution

        :return: co2 concentration in %
        :rtype: float
        """
        return self.__cc

    @cc.setter
    def cc(self, value: float) -> None:
        """
        Set current co2 concentration (%) @ storage resolution

        :param value: co2 concentration in %
        :type value: float
        """
        candidate = round(value, self.STORAGE_RESOLUTION)
        # range validation
        if 0.0 <= candidate <= 100.0:
            self.__cc = candidate
            self._cc_set = True

    @property
    def tp(self) -> float:
        """
        Get temperature setpoint (°C) @ storage resolution

        :return: temperature setpoint in °C
        :rtype: float
        """
        return self.__tp

    @tp.setter
    def tp(self, value: float) -> None:
        """
        Set temperature setpoint (°C) @ storage resolution

        :param value: temperature setpoint in °C
        :type value: float
        """
        candidate = round(value, self.STORAGE_RESOLUTION)
        # range validation
        if self.TP_RANGE[0] <= candidate <= self.TP_RANGE[1]:
            self.__tp = candidate
            self._tp_set = True

    @property
    def to(self) -> float:
        """
        Get temperature offset (°C) @ storage resolution

        :return: temperature offset in °C
        :rtype: float
        """
        return self.__to

    @to.setter
    def to(self, value: float) -> None:
        """
        Set temperature offset (°C) @ storage resolution

        :param value: temperature offset in °C
        :type value: float
        """
        candidate = round(value, self.STORAGE_RESOLUTION)
        self.__to = candidate
        self._to_set = True

    @property
    def cp(self) -> float:
        """
        Get CO2 concentration setpoint (%) @ storage resolution

        :return: CO2 concentration setpoint as %
        :rtype: float
        """
        return self.__cp

    @cp.setter
    def cp(self, value: float) -> None:
        """
        Set CO2 concentration setpoint (%) @ storage resolution

        :param value: CO2 concentration setpoint in %
        :type value: float
        """
        candidate = round(value, self.STORAGE_RESOLUTION)
        # range validation
        if self.CP_RANGE[0] <= candidate <= self.CP_RANGE[1]:
            self.__cp = candidate
            self._cp_set = True

    @property
    def op(self) -> float:
        """
        Get O2 setpoint concentration (%) @ storage resolution

        :return: O2 concentration setpoint as %
        :rtype: float
        """
        return self.__op

    @op.setter
    def op(self, value: float) -> None:
        """
        Set O2 setpoint concentration in (%) @ storage resolution

        :param value: O2 concentration setpoint as %
        :type value: float
        """
        candidate = round(value, self.STORAGE_RESOLUTION)
        # range validation
        if self.OP_RANGE[0] <= candidate <= self.OP_RANGE[1]:
            self.__op = candidate
            self._op_set = True

    @property
    def hp(self) -> int:
        """
        Get heater duty cycle (%)

        :return: heater duty cycle in percent
        :rtype: int
        """
        return self.__hp

    @hp.setter
    def hp(self, hp: int) -> None:
        """
        Set heater duty cycle (%)

        :param hp: heater duty cycle in percent
        :type hp: int
        """
        if 0 <= hp <= 100:
            self.__hp = hp
            self._hp_set = True

    @property
    def fp(self) -> int:
        """
        Get fan duty cycle (%)

        :return: fan duty cycle in percent
        :rtype: int
        """
        return self.__fp

    @fp.setter
    def fp(self, fp: int) -> None:
        """
        Set fan duty cycle (%)

        :param fp: fan duty cycle in %
        :type fp: int
        """
        if 0 <= fp <= 100:
            self.__fp = fp
            self._fp_set = True

    @property
    def fc(self) -> int:
        """
        Get current fan speed (rpm)

        :return: current fan speed in rpm
        :rtype: float
        """
        return self.__fc

    @fc.setter
    def fc(self, fc: int) -> None:
        """
        Set current fan speed (rpm)

        :param fc: current fan speed in rpm
        :type fc: int
        """
        if 0 <= fc:
            self.__fc = fc
            self._fc_set = True

    @property
    def ctr(self) -> float:
        """
        Get current COZIR temperature reading (°C)

        :return: COZIR temperature reading in °C
        :rtype: float
        """
        return self.__ctr

    @ctr.setter
    def ctr(self, ctr: float) -> None:
        """
        Set current COZIR temperature reading (°C)

        :param ctr: COZIR temperature reading (°C)
        :type ctr: float
        """
        candidate = round(ctr, 1)
        if self.OPERATING_TEMPERATURE[0] <= candidate <= self.OPERATING_TEMPERATURE[1]:
            self.__ctr = ctr
            self._ctr_set = True

    @property
    def tm(self) -> int:
        """
        Get temperature controller mode (0 -> off 1 -> read-only 2 -> active)

        :return: temperature controller mode (0 -> off 1 -> read-only 2 -> active)
        :rtype: int
        """
        return self.__tm

    @tm.setter
    def tm(self, tm: int) -> None:
        """
        Set temperature controller mode (0 -> off 1 -> read-only 2 -> active)

        :param tm: temperature controller mode (0 -> off 1 -> read-only 2 -> active)
        :type tm: int
        """
        if tm in [0, 1, 2]:
            self.__tm = tm
            self._tm_set = True

    @property
    def cm(self) -> int:
        """
        Get CO2 controller mode (0 -> off 1 -> read-only 2 -> active)

        :return: CO2 controller mode (0 -> off 1 -> read-only 2 -> active)
        :rtype: int
        """
        return self.__cm

    @cm.setter
    def cm(self, cm: int) -> None:
        """
        Set CO2 controller mode (0 -> off 1 -> read-only 2 -> active)

        :param cm: CO2 controller mode (0 -> off 1 -> read-only 2 -> active)
        :type cm: int
        """
        if cm in [0, 1, 2]:
            self.__cm = cm
            self._cm_set = True

    @property
    def om(self) -> int:
        """
        Get O2 controller mode (0 -> off 1 -> read-only 2 -> active)

        :return: o2 controller mode
        :rtype: int
        """
        return self.__om

    @om.setter
    def om(self, om: int) -> None:
        """
        Set O2 controller mode (0 -> off 1 -> read-only 2 -> active)

        :param om: 0 -> off 1 -> read-only 2 -> active
        :type om: int
        """
        if om in [0, 1, 2]:
            self.__om = om
            self._om_set = True

    @property
    def iv(self) -> str:
        """
        Get icb version string

        :return: icb git sha
        :rtype: str
        """
        return self.__iv

    @iv.setter
    def iv(self, version: str) -> None:
        """
        Set icb version string

        :param version: icb git sha
        :type version: str
        """
        self.__iv = version
        self._iv_set = True

    @property
    def timestamp(self) -> str:
        """
        Get timestamp of sensorframe reading as an ISO string

        :return: timestamp of previous sensorframe reading in iso format
        :rtype: str
        """
        return self.__timestamp

    @timestamp.setter
    def timestamp(self, timestamp: str) -> None:
        """
        Set timestamp of sensorframe reading as an ISO string

        :param timestamp: timestamp of sensorframe reading in iso format
        :type timestamp: str
        """
        self.__timestamp = timestamp
        self._timestamp_set = True

    @property
    def ct(self) -> str:
        """
        Get last co2 sensor calibration time as ISO timestamp
        """
        return self.__ct

    @ct.setter
    def ct(self, ct: str) -> None:
        """
        Set co2 calibration time in iso format (UTC)

        :param ct: calibration time in utc iso format
        :type ct: str
        """
        self.__ct = ct
        self._ct_set = True

    def int_to_float(self, val: int) -> float:
        """
        Convert int setpoint @ conversion resolution to iris compatible float

        :param val: input integer value
        :type val: int
        :return: output float value
        :rtype: float
        """
        return val / (10 ** self.CONVERSION_RESOLUTION)

    def float_to_int(self, val: float) -> int:
        """
        Convert float setpoint @ conversion resolution to icb compatible integer

        :param val: input float value
        :type val: float
        :return: output integer value
        :rtype: int
        """
        return int(val * (10 ** self.CONVERSION_RESOLUTION))

    @staticmethod
    def generate_timestamp() -> str:
        """
        Generate iso timestamp (UTC)

        :return: iso format timestamp in base utc
        :rtype: str
        """
        return datetime.now(timezone.utc).replace(microsecond=0).isoformat()

    @staticmethod
    def calibration_time_to_iso(ct: int) -> str:
        """
        Convert 12hr. unit timestamp to iso datetime format in utc

        :param ct: 12hr. units
        :type ct: int
        :return: iso datetime
        :rtype: str
        """
        return datetime.fromtimestamp(ct * 12 * 60 * 60).isoformat()

    @staticmethod
    def generate_co2_calibration_time() -> int:
        """
        Generate a co2 calibration timestamp in 12hr. units

        :return: calibration timestamp in 12hr. units
        :rtype: int
        """
        return int(datetime.now(timezone.utc).timestamp() / 60 / 60 / 12)

    @staticmethod
    def generate_id() -> str:
        """
        Generate uuid for this instance

        :return: [description]
        :rtype: str
        """
        return uuid4().hex


"""
Tests to ensure that NSDictionary and NSMutableDictionary conform
to the python dict interface

These tests are basicly a port of the Python 3.2 tests for dictionaries
and dictionary views.

TODO:
- Port all tests
- Do the same for python 2.x
- Do the same for sets (NSSet) and lists (NSArray)
"""
import collections.abc

# Import some of the stdlib tests
from test import mapping_tests

import objc
from PyObjCTools.TestSupport import TestCase

NSDictionary = objc.lookUpClass("NSDictionary")
NSMutableDictionary = objc.lookUpClass("NSMutableDictionary")

class TestNSDictionaryInterface(TestCase):
    def dictClass(self):
        return NSDictionary

    def createDictionary(self, **kwds):
        return NSDictionary.dictionaryWithDictionary_(kwds)

    def testConstructor(self):
        value = self.dictClass()()
        self.assertEqual(value, {})

    def testBool(self):
        self.assertIs(not self.createDictionary(), True)
        self.assertTrue(self.createDictionary(foo="1"))
        self.assertIs(bool(self.createDictionary()), False)
        self.assertIs(bool(self.createDictionary(foo="1")), True)

    def testKeys(self):
        d = self.createDictionary()
        self.assertEqual(set(d.keys()), set())

        d = self.createDictionary(a=1, b=2)
        k = d.keys()

        self.assertIn("a", d)
        self.assertIn("b", d)
        self.assertIn("a", k)
        self.assertIn("b", k)

        self.assertNotIsInstance(k, list)

        s = d.keys() | {"c"}
        self.assertEqual(s, {"a", "b", "c"})

        s = {"c"} | d.keys()
        self.assertEqual(s, {"a", "b", "c"})

        s = d.keys() & {"b"}
        self.assertEqual(s, {"b"})

        s = {"b", "c"} & d.keys()
        self.assertEqual(s, {"b"})

        s = d.keys() - {"b"}
        self.assertEqual(s, {"a"})

        s = {"c", "b"} - d.keys()
        self.assertEqual(s, {"c"})

        s = d.keys() ^ {"b", "c"}
        self.assertEqual(s, {"a", "c"})

        s = {"c", "b"} ^ d.keys()
        self.assertEqual(s, {"a", "c"})

        self.assertEqual(
            repr(self.createDictionary(a=1).keys()), "<nsdict_keys(['a'])>"
        )

    def testValues(self):
        d = self.createDictionary()
        self.assertEqual(set(d.values()), set())

        d = self.createDictionary(a=1)

        self.assertEqual(set(d.values()), {1})
        with self.assertRaisesRegex(
            TypeError, r".*\(\) takes 1 positional argument but 2 were given"
        ):
            d.values(None)
        self.assertNotIsInstance(d.values(), list)

        self.assertEqual(
            repr(self.createDictionary(a=1).values()), "<nsdict_values([1])>"
        )

    def testItems(self):
        d = self.createDictionary()
        self.assertEqual(set(d.items()), set())

        d = self.createDictionary(a=1)
        self.assertEqual(set(d.items()), {("a", 1)})
        with self.assertRaisesRegex(
            TypeError, r".*\(\) takes 1 positional argument but 2 were given"
        ):
            d.items(None)
        self.assertEqual(
            repr(self.createDictionary(a=1).items()), "<nsdict_items([('a', 1)])>"
        )

    def testContains(self):
        d = self.createDictionary()
        self.assertNotIn("a", d)
        self.assertFalse("a" in d)
        self.assertTrue("a" not in d)

        d = self.createDictionary(a=1, b=2)
        self.assertIn("a", d)
        self.assertIn("b", d)
        self.assertNotIn("c", d)

        with self.assertRaisesRegex(
            TypeError, r".*\(\) missing 1 required positional argument: 'key'"
        ):
            d.__contains__()

    def testLen(self):
        d = self.createDictionary()
        self.assertEqual(len(d), 0)

        d = self.createDictionary(a=1, b=2)
        self.assertEqual(len(d), 2)

    def testGetItem(self):
        d = self.createDictionary(a=1, b=2)
        self.assertEqual(d["a"], 1)
        self.assertEqual(d["b"], 2)

        with self.assertRaisesRegex(
            TypeError, r".*\(\) missing 1 required positional argument: 'key'"
        ):
            d.__getitem__()

    def testFromKeys(self):
        d = self.dictClass().fromkeys("abc")
        self.assertEqual(d, {"a": None, "b": None, "c": None})

        d = self.createDictionary()
        self.assertIsNot(d.fromkeys("abc"), d)
        self.assertEqual(d.fromkeys("abc"), {"a": None, "b": None, "c": None})
        self.assertEqual(d.fromkeys((4, 5), 0), {4: 0, 5: 0})
        self.assertEqual(d.fromkeys([]), {})

        def g():
            yield 1

        self.assertEqual(d.fromkeys(g()), {1: None})
        with self.assertRaisesRegex(TypeError, "'int' object is not iterable"):
            {}.fromkeys(3)

        d = self.dictClass()(zip(range(6), range(6)))
        self.assertEqual(dict.fromkeys(d, 0), dict(zip(range(6), [0] * 6)))

    def _testCopy(self):
        self.fail("Decide what to do w.r.t. -copy and -mutableCopy")

    def testGet(self):
        d = self.createDictionary()
        self.assertIs(d.get("c"), None)
        self.assertEqual(d.get("c", 3), 3)

        d = self.createDictionary(a=1, b=2)
        self.assertIs(d.get("c"), None)
        self.assertEqual(d.get("c", 3), 3)
        self.assertEqual(d.get("a"), 1)
        self.assertEqual(d.get("a", 3), 1)
        with self.assertRaisesRegex(
            TypeError, r".*\(\) missing 1 required positional argument: 'key'"
        ):
            d.get()
        with self.assertRaisesRegex(
            TypeError, r".*\(\) takes from 2 to 3 positional arguments but 4 were given"
        ):
            d.get(None, None, None)

    def testEq(self):
        self.assertEqual(self.createDictionary(), self.createDictionary())
        self.assertEqual(self.createDictionary(a=1), self.createDictionary(a=1))

        class Exc(Exception):
            pass

        class BadCmp:
            def __eq__(self, other):
                raise Exc()

            def __hash__(self):
                return 1

        d1 = {BadCmp(): 1}
        d2 = {BadCmp(): 1}

        with self.assertRaises(Exc):
            d1 == d2  # noqa: B015

    def testKeysContained(self):
        self.helper_keys_contained(lambda x: x.keys())
        self.helper_keys_contained(lambda x: x.items())

    def helper_keys_contained(self, fn):
        # Test rich comparisons against dict key views, which should behave the
        # same as sets.

        empty = fn(self.createDictionary())
        empty2 = fn(self.createDictionary())
        smaller = fn(self.createDictionary(a=1, b=2))
        larger = fn(self.createDictionary(a=1, b=2, c=3))
        larger2 = fn(self.createDictionary(a=1, b=2, c=3))
        larger3 = fn(self.createDictionary(d=1, b=2, c=3))

        self.assertTrue(smaller < larger)
        self.assertTrue(smaller <= larger)
        self.assertTrue(larger > smaller)
        self.assertTrue(larger >= smaller)

        self.assertFalse(smaller >= larger)
        self.assertFalse(smaller > larger)
        self.assertFalse(larger <= smaller)
        self.assertFalse(larger < smaller)

        self.assertFalse(smaller < larger3)
        self.assertFalse(smaller <= larger3)
        self.assertFalse(larger3 > smaller)
        self.assertFalse(larger3 >= smaller)

        # Inequality strictness
        self.assertTrue(larger2 >= larger)
        self.assertTrue(larger2 <= larger)
        self.assertFalse(larger2 > larger)
        self.assertFalse(larger2 < larger)

        self.assertTrue(larger == larger2)
        self.assertTrue(smaller != larger)

        # There is an optimization on the zero-element case.
        self.assertTrue(empty == empty2)
        self.assertFalse(empty != empty2)
        self.assertFalse(empty == smaller)
        self.assertTrue(empty != smaller)

        # With the same size, an elementwise compare happens
        self.assertTrue(larger != larger3)
        self.assertFalse(larger == larger3)

    def testErrorsInViewContainmentCheck(self):
        class C:
            def __eq__(self, other):
                raise RuntimeError()

        d1 = self.dictClass().dictionaryWithDictionary_({1: C()})
        d2 = self.dictClass().dictionaryWithDictionary_({1: C()})

        with self.assertRaises(RuntimeError):
            d1.items() == d2.items()  # noqa: B015
        with self.assertRaises(RuntimeError):
            d1.items() != d2.items()  # noqa: B015
        with self.assertRaises(RuntimeError):
            d1.items() <= d2.items()  # noqa: B015
        with self.assertRaises(RuntimeError):
            d1.items() >= d2.items()  # noqa: B015

        d3 = self.dictClass().dictionaryWithDictionary_({1: C(), 2: C()})
        with self.assertRaises(RuntimeError):
            d2.items() < d3.items()  # noqa: B015
        with self.assertRaises(RuntimeError):
            d3.items() > d2.items()  # noqa: B015

        k1 = self.dictClass().dictionaryWithDictionary_({1: 1, 2: 2}).keys()
        k2 = self.dictClass().dictionaryWithDictionary_({1: 1, 2: 2, 3: 3}).keys()
        k3 = self.dictClass().dictionaryWithDictionary_({4: 4}).keys()

        self.assertEqual(k1 - k2, set())
        self.assertEqual(k1 - k3, {1, 2})
        self.assertEqual(k2 - k1, {3})
        self.assertEqual(k3 - k1, {4})
        self.assertEqual(k1 & k2, {1, 2})
        self.assertEqual(k1 & k3, set())
        self.assertEqual(k1 | k2, {1, 2, 3})
        self.assertEqual(k1 ^ k2, {3})
        self.assertEqual(k1 ^ k3, {1, 2, 4})

    def testDictviewSetOperationsOnItems(self):
        k1 = self.dictClass().dictionaryWithDictionary_({1: 1, 2: 2}).items()
        k2 = self.dictClass().dictionaryWithDictionary_({1: 1, 2: 2, 3: 3}).items()
        k3 = self.dictClass().dictionaryWithDictionary_({4: 4}).items()

        self.assertEqual(k1 - k2, set())
        self.assertEqual(k1 - k3, {(1, 1), (2, 2)})
        self.assertEqual(k2 - k1, {(3, 3)})
        self.assertEqual(k3 - k1, {(4, 4)})
        self.assertEqual(k1 & k2, {(1, 1), (2, 2)})
        self.assertEqual(k1 & k3, set())
        self.assertEqual(k1 | k2, {(1, 1), (2, 2), (3, 3)})
        self.assertEqual(k1 ^ k2, {(3, 3)})
        self.assertEqual(k1 ^ k3, {(1, 1), (2, 2), (4, 4)})

    def testDictviewMixedSetOperations(self):
        # Just a few for .keys()
        self.assertTrue(
            self.dictClass().dictionaryWithDictionary_({1: 1}).keys() == {1}
        )
        self.assertTrue(
            {1} == self.dictClass().dictionaryWithDictionary_({1: 1}).keys()
        )
        self.assertEqual(
            self.dictClass().dictionaryWithDictionary_({1: 1}).keys() | {2}, {1, 2}
        )
        self.assertEqual(
            {2} | self.dictClass().dictionaryWithDictionary_({1: 1}).keys(), {1, 2}
        )
        self.assertFalse(
            self.dictClass().dictionaryWithDictionary_({1: 1}).keys() == [1]
        )

        # And a few for .items()
        self.assertTrue(
            self.dictClass().dictionaryWithDictionary_({1: 1}).items() == {(1, 1)}
        )
        self.assertTrue(
            {(1, 1)} == self.dictClass().dictionaryWithDictionary_({1: 1}).items()
        )
        self.assertEqual(
            self.dictClass().dictionaryWithDictionary_({1: 1}).items() | {2},
            {(1, 1), 2},
        )
        self.assertEqual(
            {2} | self.dictClass().dictionaryWithDictionary_({1: 1}).items(),
            {(1, 1), 2},
        )
        self.assertFalse(
            self.dictClass().dictionaryWithDictionary_({1: 1}).items() == [(1, 1)]
        )

class TestNSMutableDictionaryInterface(TestNSDictionaryInterface):
    def dictClass(self):
        return NSMutableDictionary

    def createDictionary(self, **kwds):
        return NSMutableDictionary.dictionaryWithDictionary_(kwds)

    def testKeysMutable(self):
        d = self.createDictionary()
        self.assertEqual(set(d.keys()), set())

        d = self.createDictionary(a=1, b=2)
        k = d.keys()

        self.assertIn("a", d)
        self.assertIn("b", d)
        self.assertIn("a", k)
        self.assertIn("b", k)

        self.assertNotIsInstance(k, list)

        self.assertNotIn("c", d)
        self.assertNotIn("c", k)

        d["c"] = 3
        self.assertIn("c", d)
        self.assertIn("c", k)

    def testValuesMutable(self):
        d = self.createDictionary()
        self.assertEqual(set(d.values()), set())

        d = self.createDictionary(a=1)
        v = d.values()

        self.assertEqual(set(v), {1})

        d["b"] = 2
        self.assertEqual(set(v), {1, 2})

    def testItemsMutable(self):
        d = self.createDictionary()
        self.assertEqual(set(d.items()), set())

        d = self.createDictionary(a=1)
        i = d.items()

        self.assertEqual(set(i), {("a", 1)})

        d["b"] = 2

        self.assertEqual(set(i), {("a", 1), ("b", 2)})

    def testGetItem(self):
        d = self.createDictionary(a=1, b=2)
        self.assertEqual(d["a"], 1)
        self.assertEqual(d["b"], 2)

        d["c"] = 3
        d["a"] = 4
        self.assertEqual(d["c"], 3)
        self.assertEqual(d["a"], 4)
        del d["b"]
        self.assertEqual(d, {"a": 4, "c": 3})

        with self.assertRaisesRegex(
            TypeError, r".*\(\) missing 1 required positional argument: 'key'"
        ):
            d.__getitem__()

        class Exc(Exception):
            pass

        class BadEq:
            def __eq__(self, other):
                raise Exc()

            def __hash__(self):
                return hash(23)

        d = self.createDictionary()
        d[BadEq()] = 42
        with self.assertRaisesRegex(KeyError, "23"):
            d.__getitem__(23)

        class BadHash:
            fail = False

            def __hash__(self):
                if self.fail:
                    raise Exc()
                else:
                    return 42

        d = self.createDictionary()
        x = BadHash()
        d[x] = 42
        x.fail = True

        # FIXME
        # with self.assertRaises(Exc):
        #    d[x]

    def testClear(self):
        d = self.createDictionary(a=1, b=2, c=3)
        d.clear()

        self.assertEqual(d, {})

        with self.assertRaisesRegex(
            TypeError, r".*\(\) takes 1 positional argument but 2 were given"
        ):
            d.clear(None)

    def testUpdate(self):
        d = self.createDictionary()
        d.update({1: 100})
        d.update({2: 20})
        d.update({1: 1, 2: 2, 3: 3})
        self.assertEqual(d, {1: 1, 2: 2, 3: 3})

        d.update()
        self.assertEqual(d, {1: 1, 2: 2, 3: 3})

        with self.assertRaisesRegex(
            (TypeError, AttributeError), "'NoneType' object is not iterable"
        ):
            d.update(None)

        class SimpleUserDict:
            def __init__(self):
                self.d = {1: 1, 2: 2, 3: 3}

            def keys(self):
                return self.d.keys()

            def __getitem__(self, i):
                return self.d[i]

        d = self.createDictionary()
        d.update(SimpleUserDict())
        self.assertEqual(d, {1: 1, 2: 2, 3: 3})

        class Exc(Exception):
            pass

        d.clear()

        class FailingUserDict:
            def keys(self):
                raise Exc()

        with self.assertRaises(Exc):
            d.update(FailingUserDict())

        class FailingUserDict:
            def keys(self):
                class BogonIter:
                    def __init__(self):
                        self.i = 1

                    def __iter__(self):
                        return self

                    def __next__(self):
                        if self.i:
                            self.i = 0
                            return "a"
                        raise Exc

                return BogonIter()

            def __getitem__(self, key):
                return key

        with self.assertRaises(Exc):
            d.update(FailingUserDict())

        class FailingUserDict:
            def keys(self):
                class BogonIter:
                    def __init__(self):
                        self.i = ord("a")

                    def __iter__(self):
                        return self

                    def __next__(self):
                        if self.i <= ord("z"):
                            rtn = chr(self.i)
                            self.i += 1
                            return rtn
                        raise StopIteration

                return BogonIter()

            def __getitem__(self, key):
                raise Exc

        with self.assertRaises(Exc):
            d.update(FailingUserDict())

        class badseq:
            def __iter__(self):
                return self

            def __next__(self):
                raise Exc()

        with self.assertRaises(Exc):
            {}.update(badseq())
            with self.assertRaisesRegex(ValueError, "foo"):
                {}.update([(1, 2, 3)])

    def setDefault(self):
        d = self.createDictionary()
        self.assertIs(d.setdefault("key0"), None)
        d.setdefault("key0", [])
        self.assertIs(d.setdefault("key0"), None)
        d.setdefault("key", []).append(3)
        self.assertEqual(d["key"][0], 3)
        d.setdefault("key", []).append(4)
        self.assertEqual(len(d["key"]), 2)
        with self.assertRaisesRegex(TypeError, "foo"):
            d.setdefault()

        class Exc(Exception):
            pass

        class BadHash:
            fail = False

            def __hash__(self):
                if self.fail:
                    raise Exc()
                else:
                    return 42

        x = BadHash()
        d[x] = 42
        x.fail = True
        with self.assertRaises(Exc):
            d.setdefault(x, [])

    def testPopitem(self):
        for copymode in -1, +1:
            # -1: b has same structure as a
            # +1: b is a.copy()
            for log2size in range(12):
                size = 2**log2size
                a = self.createDictionary()
                b = self.createDictionary()
                for i in range(size):
                    a[repr(i)] = i
                    if copymode < 0:
                        b[repr(i)] = i
                if copymode > 0:
                    b = a.mutableCopy()
                for _ in range(size):
                    ka, va = ta = a.popitem()
                    self.assertEqual(va, int(ka))
                    kb, vb = tb = b.popitem()
                    self.assertEqual(vb, int(kb))
                    self.assertFalse(copymode < 0 and ta != tb)
                self.assertFalse(a)
                self.assertFalse(b)

        d = self.createDictionary()
        with self.assertRaisesRegex(
            KeyError, "'popitem on an empty [A-Z0-9_]*NSDictionary[A-Z0-9_]*"
        ):
            d.popitem()

    def testPop(self):
        d = self.createDictionary()
        k, v = "abc", "def"
        d[k] = v
        with self.assertRaisesRegex(KeyError, "^'ghi'$"):
            d.pop("ghi")

        self.assertEqual(d.pop(k), v)
        self.assertEqual(len(d), 0)

        with self.assertRaisesRegex(KeyError, k):
            d.pop(k)

        self.assertEqual(d.pop(k, v), v)
        d[k] = v
        self.assertEqual(d.pop(k, 1), v)

        with self.assertRaisesRegex(
            TypeError, r".*\(\) missing 1 required positional argument: 'key'"
        ):
            d.pop()

        class Exc(Exception):
            pass

        class BadHash:
            fail = False

            def __hash__(self):
                if self.fail:
                    raise Exc()
                else:
                    return 42

        # XXX
        # x = BadHash()
        # d[x] = 42
        # x.fail = True
        # with self.assertRaises(Exc): d.pop( x)

class DictSetTest(TestCase):
    dictclass = NSDictionary

    def testDictKeys(self):
        d = self.dictclass.dictionaryWithDictionary_({1: 10, "a": "ABC"})

        keys = d.keys()

        self.assertEqual(len(keys), 2)
        self.assertEqual(set(keys), {1, "a"})
        self.assertEqual(keys, {1, "a"})
        self.assertNotEqual(keys, {1, "a", "b"})
        self.assertNotEqual(keys, {1, "b"})
        self.assertNotEqual(keys, {1})
        self.assertNotEqual(keys, 42)
        self.assertIn(1, keys)
        self.assertIn("a", keys)
        self.assertNotIn(10, keys)
        self.assertNotIn("Z", keys)
        self.assertEqual(d.keys(), d.keys())

        e = self.dictclass.dictionaryWithDictionary_({1: 11, "a": "def"})
        self.assertEqual(d.keys(), e.keys())

    def testDictItems(self):
        d = self.dictclass.dictionaryWithDictionary_({1: 10, "a": "ABC"})
        items = d.items()

        self.assertEqual(len(items), 2)
        self.assertEqual(set(items), {(1, 10), ("a", "ABC")})
        self.assertEqual(items, {(1, 10), ("a", "ABC")})
        self.assertNotEqual(items, {(1, 10), ("a", "ABC"), "junk"})
        self.assertNotEqual(items, {(1, 10), ("a", "def")})
        self.assertNotEqual(items, {(1, 10)})
        self.assertNotEqual(items, 42)
        self.assertIn((1, 10), items)
        self.assertIn(("a", "ABC"), items)
        self.assertNotIn((1, 11), items)
        self.assertNotIn(1, items)
        self.assertNotIn((), items)
        self.assertNotIn((1,), items)
        self.assertNotIn((1, 2, 3), items)
        self.assertEqual(d.items(), d.items())

        e = d.copy()
        self.assertEqual(d.items(), e.items())

class DictSetTest(DictSetTest):
    dictclass = NSMutableDictionary

    def testDictKeysMutable(self):
        d = self.dictclass.dictionaryWithDictionary_({1: 10, "a": "ABC"})
        e = self.dictclass.dictionaryWithDictionary_({1: 11, "a": "def"})
        self.assertEqual(d.keys(), e.keys())

        del e["a"]
        self.assertNotEqual(d.keys(), e.keys())

    def testDictItemsMutable(self):
        d = self.dictclass.dictionaryWithDictionary_({1: 10, "a": "ABC"})

        e = d.copy()
        self.assertEqual(d.items(), e.items())
        d["a"] = "def"
        self.assertNotEqual(d.items(), e.items())

    def testDictMixedKeysItems(self):
        d = self.dictclass.dictionaryWithDictionary_({(1, 1): 11, (2, 2): 22})
        e = self.dictclass.dictionaryWithDictionary_({1: 1, 2: 2})
        self.assertEqual(d.keys(), e.items())
        self.assertNotEqual(d.items(), e.keys())

    def testDictValues(self):
        d = self.dictclass.dictionaryWithDictionary_({1: 10, "a": "ABC"})
        values = d.values()
        self.assertEqual(set(values), {10, "ABC"})
        self.assertEqual(len(values), 2)

class GeneralMappingTestsNSMutableDictionary(mapping_tests.BasicTestMappingProtocol):
    type2test = NSMutableDictionary

class TestDictUpdates(TestCase):
    def do_test(self, dictType):
        d = dictType()
        d["a"] = 42
        with self.assertRaisesRegex(
            TypeError, "update expected at most 1 argument(s)?, got 2"
        ):
            d.update({}, {})

        d.update({"b": 9})
        self.assertEqual(dict(d), {"a": 42, "b": 9})

        d.update({"a": 2})
        self.assertEqual(dict(d), {"a": 2, "b": 9})

        d.update([("a", 1), ("c", 3)])
        self.assertEqual(dict(d), {"a": 1, "b": 9, "c": 3})

        d.update(d=4, a=9, e=3)
        self.assertEqual(dict(d), {"a": 9, "b": 9, "c": 3, "d": 4, "e": 3})

        d.update()
        self.assertEqual(dict(d), {"a": 9, "b": 9, "c": 3, "d": 4, "e": 3})

    def test_native(self):
        self.do_test(dict)

    def test_objc(self):
        self.do_test(NSMutableDictionary)

class TestABC(TestCase):
    def testDictABC(self):
        self.assertTrue(issubclass(NSDictionary, collections.abc.Mapping))
        self.assertTrue(issubclass(NSMutableDictionary, collections.abc.Mapping))
        self.assertTrue(issubclass(NSMutableDictionary, collections.abc.MutableMapping))

    def testViewABC(self):
        d = NSDictionary.dictionary()
        self.assertTrue(isinstance(d.keys(), collections.abc.KeysView))
        self.assertTrue(isinstance(d.values(), collections.abc.ValuesView))
        self.assertTrue(isinstance(d.items(), collections.abc.ItemsView))

        d = NSMutableDictionary.dictionary()
        self.assertTrue(isinstance(d.keys(), collections.abc.KeysView))
        self.assertTrue(isinstance(d.values(), collections.abc.ValuesView))
        self.assertTrue(isinstance(d.items(), collections.abc.ItemsView))

class TestPyObjCDict(TestCase):
    def test_comparison(self):
        with self.assertRaisesRegex(
            TypeError, "'<' not supported between instances of 'dict' and 'dict'"
        ):
            {} < {}  # noqa: B015
        with self.assertRaisesRegex(
            TypeError, "'<=' not supported between instances of 'dict' and 'dict'"
        ):
            {} <= {}  # noqa: B015
        with self.assertRaisesRegex(
            TypeError, "'>' not supported between instances of 'dict' and 'dict'"
        ):
            {} > {}  # noqa: B015
        with self.assertRaisesRegex(
            TypeError, "'>=' not supported between instances of 'dict' and 'dict'"
        ):
            {} >= {}  # noqa: B015

        with self.assertRaisesRegex(
            TypeError,
            "'<' not supported between instances of '[^']*NSDictionary[^']*' and 'dict'",
        ):
            NSDictionary() < {}  # noqa: B015
        with self.assertRaisesRegex(
            TypeError,
            "'<=' not supported between instances of '[^']*NSDictionary[^']*' and 'dict'",
        ):
            NSDictionary() <= {}  # noqa: B015
        with self.assertRaisesRegex(
            TypeError,
            "'>' not supported between instances of '[^']*NSDictionary[^']*' and 'dict'",
        ):
            NSDictionary() > {}  # noqa: B015
        with self.assertRaisesRegex(
            TypeError,
            "'>=' not supported between instances of '[^']*NSDictionary[^']*' and 'dict'",
        ):
            NSDictionary() >= {}  # noqa: B015
        with self.assertRaisesRegex(
            TypeError,
            "'<' not supported between instances of 'dict' and '[^']*NSDictionary[^']*'",
        ):
            {} < NSDictionary()  # noqa: B015
        with self.assertRaisesRegex(
            TypeError,
            "'<=' not supported between instances of 'dict' and '[^']*NSDictionary[^']*'",
        ):
            {} <= NSDictionary()  # noqa: B015
        with self.assertRaisesRegex(
            TypeError,
            "'>' not supported between instances of 'dict' and '[^']*NSDictionary[^']*'",
        ):
            {} > NSDictionary()  # noqa: B015
        with self.assertRaisesRegex(
            TypeError,
            "'>=' not supported between instances of 'dict' and '[^']*NSDictionary[^']*'",
        ):
            {} >= NSDictionary()  # noqa: B015

        self.assertFalse(NSMutableDictionary() == [])
        self.assertFalse(NSDictionary() == [])
        self.assertFalse(NSMutableDictionary() == 42)
        self.assertFalse(NSDictionary() == 42)
        self.assertFalse(NSMutableDictionary() == object())
        self.assertFalse(NSDictionary() == object())

    def test_creation(self):
        for dict_type in (NSDictionary, NSMutableDictionary):
            v = dict_type()
            self.assertIsInstance(v, dict_type)
            self.assertEqual(len(v), 0)

            v = dict_type({1: 2, 2: 3})
            self.assertIsInstance(v, dict_type)
            self.assertEqual(len(v), 2)
            self.assertEqual(v[1], 2)
            self.assertEqual(v[2], 3)

            v = dict_type([(1, -1), (2, 9)])
            self.assertIsInstance(v, dict_type)
            self.assertEqual(len(v), 2)
            self.assertEqual(v[1], -1)
            self.assertEqual(v[2], 9)

            v = dict_type(v for v in [(1, -1), (2, 9)])
            self.assertIsInstance(v, dict_type)
            self.assertEqual(len(v), 2)
            self.assertEqual(v[1], -1)
            self.assertEqual(v[2], 9)

            with self.assertRaisesRegex(
                TypeError, "dict expected at most 1 arguments, got 2"
            ):
                dict_type((1, 2), (3, 4))

            v = dict_type(a=3, b=4)
            self.assertEqual(len(v), 2)
            self.assertEqual(v["a"], 3)
            self.assertEqual(v["b"], 4)

            v = dict_type((v for v in [(1, -1), (2, 9)]), a="hello", b="world")
            self.assertIsInstance(v, dict_type)
            self.assertEqual(len(v), 4)
            self.assertEqual(v[1], -1)
            self.assertEqual(v[2], 9)
            self.assertEqual(v["a"], "hello")
            self.assertEqual(v["b"], "world")

    def test_values(self):
        py = {"a": 4, "b": 3}
        oc = NSDictionary(a=4, b=3)

        self.assertIn(4, py.values())
        self.assertIn(4, oc.values())
        self.assertNotIn(9, py.values())
        self.assertNotIn(9, oc.values())

    def test_view_set(self):
        oc = NSDictionary(a=1, b=2, c=3, d=4, e=5)

        v = oc.keys() | {"a", "f"}
        self.assertEqual(v, {"a", "b", "c", "d", "e", "f"})
        self.assertIsInstance(v, set)
        with self.assertRaisesRegex(
            TypeError, r"unsupported operand type\(s\) for |: 'nsdict_keys' and 'tuple'"
        ):
            oc.keys() | ("a", "f")
        with self.assertRaisesRegex(
            TypeError, r"unsupported operand type\(s\) for |: 'tuple' and 'nsdict_keys'"
        ):
            ("a", "f") | oc.keys()

        v = oc.keys() & {"a", "f"}
        self.assertEqual(v, {"a"})
        self.assertIsInstance(v, set)
        with self.assertRaisesRegex(
            TypeError, r"unsupported operand type\(s\) for &: 'nsdict_keys' and 'tuple'"
        ):
            oc.keys() & ("a", "f")
        with self.assertRaisesRegex(
            TypeError, r"unsupported operand type\(s\) for &: 'tuple' and 'nsdict_keys'"
        ):
            ("a", "f") & oc.keys()

        v = oc.keys() ^ {"a", "f"}
        self.assertEqual(v, {"b", "c", "d", "e", "f"})
        self.assertIsInstance(v, set)
        with self.assertRaisesRegex(
            TypeError,
            r"unsupported operand type\(s\) for \^: 'nsdict_keys' and 'tuple'",
        ):
            oc.keys() ^ ("a", "f")
        with self.assertRaisesRegex(
            TypeError,
            r"unsupported operand type\(s\) for \^: 'tuple' and 'nsdict_keys'",
        ):
            ("a", "f") ^ oc.keys()

        v = oc.keys() - {"a", "f"}
        self.assertEqual(v, {"b", "c", "d", "e"})
        self.assertIsInstance(v, set)
        with self.assertRaisesRegex(
            TypeError, r"unsupported operand type\(s\) for -: 'nsdict_keys' and 'tuple'"
        ):
            oc.keys() - ("a", "f")
        with self.assertRaisesRegex(
            TypeError, r"unsupported operand type\(s\) for -: 'tuple' and 'nsdict_keys'"
        ):
            ("a", "f") - oc.keys()

        with self.assertRaisesRegex(
            TypeError,
            r"'<' not supported between instances of 'nsdict_keys' and 'tuple'",
        ):
            oc.keys() < ("a", "f")  # noqa: B015
        with self.assertRaisesRegex(
            TypeError,
            r"'<=' not supported between instances of 'nsdict_keys' and 'tuple'",
        ):
            oc.keys() <= ("a", "f")  # noqa: B015
        with self.assertRaisesRegex(
            TypeError,
            r"'>' not supported between instances of 'nsdict_keys' and 'tuple'",
        ):
            oc.keys() > ("a", "f")  # noqa: B015
        with self.assertRaisesRegex(
            TypeError,
            r"'>=' not supported between instances of 'nsdict_keys' and 'tuple'",
        ):
            oc.keys() >= ("a", "f")  # noqa: B015


from django.shortcuts import render

## 사용자 브라우저로 응답을 하기우한 라이브러리
from django.shortcuts import HttpResponse

# Create your views here.

def testpage(request):
    return HttpResponse("django ok")

## 최초페이지
def index(request):
    msg="""

 index page 입니다.

            html 코드 잘 실행됩니다,

        """
    #return HttpResponse(msg)
    return render(request,
                  "firstapp/index.html",
                  {"key":"value잘나오오오오오오옴 d",
                   "key1":"value2잘2222222222222222옴 d",})

def index(request):
    return render(request,
                  "firstapp/index.html",
                  {"key":"value잘나오오오오오오옴 d",
                   "key1":"value2잘2222222222222222옴 d",})


import shutil
from argparse import Namespace
from typing import List
import dgl
import numpy as np
import torch
import torch.distributed as dist
import torchvision.transforms.functional as F
from PIL import Image
from PIL import ImageOps
from rdkit import Chem
from sklearn.linear_model import LinearRegression

# Atom feature sizes
MAX_ATOMIC_NUM = 100
ATOM_FEATURES = {
    'atomic_num': list(range(MAX_ATOMIC_NUM)),
    'degree': [0, 1, 2, 3, 4, 5],
    'formal_charge': [-1, -2, 1, 2, 0],
    'chiral_tag': [0, 1, 2, 3],
    'num_Hs': [0, 1, 2, 3, 4],
    'hybridization': [
        Chem.rdchem.HybridizationType.SP,
        Chem.rdchem.HybridizationType.SP2,
        Chem.rdchem.HybridizationType.SP3,
        Chem.rdchem.HybridizationType.SP3D,
        Chem.rdchem.HybridizationType.SP3D2
    ],
}

# Distance feature sizes
PATH_DISTANCE_BINS = list(range(10))
THREE_D_DISTANCE_MAX = 20
THREE_D_DISTANCE_STEP = 1
THREE_D_DISTANCE_BINS = list(range(0, THREE_D_DISTANCE_MAX + 1, THREE_D_DISTANCE_STEP))

# len(choices) + 1 to include room for uncommon values; + 2 at end for IsAromatic and mass
ATOM_FDIM = sum(len(choices) + 1 for choices in ATOM_FEATURES.values()) + 2
BOND_FDIM = 14

def get_atom_fdim(args: Namespace) -> int:
    """
    Gets the dimensionality of atom features.

    :param: Arguments.
    """
    return ATOM_FDIM

def get_bond_fdim(args: Namespace) -> int:
    """
    Gets the dimensionality of bond features.

    :param: Arguments.
    """
    return BOND_FDIM

def onek_encoding_unk(value: int, choices: List[int]) -> List[int]:
    """
    Creates a one-hot encoding.

    :param value: The value for which the encoding should be one.
    :param choices: A list of possible values.
    :return: A one-hot encoding of the value in a list of length len(choices) + 1.
    If value is not in the list of choices, then the final element in the encoding is 1.
    """
    encoding = [0] * (len(choices) + 1)
    index = choices.index(value) if value in choices else -1
    encoding[index] = 1

    return encoding

def atom_features(atom: Chem.rdchem.Atom, functional_groups: List[int] = None):
    """
    Builds a feature vector for an atom.

    :param atom: An RDKit atom.
    :param functional_groups: A k-hot vector indicating the functional groups the atom belongs to.
    :return: A list containing the atom features.
    """
    features = onek_encoding_unk(atom.GetAtomicNum() - 1, ATOM_FEATURES['atomic_num']) + \
               onek_encoding_unk(atom.GetTotalDegree(), ATOM_FEATURES['degree']) + \
               onek_encoding_unk(atom.GetFormalCharge(), ATOM_FEATURES['formal_charge']) + \
               onek_encoding_unk(int(atom.GetChiralTag()), ATOM_FEATURES['chiral_tag']) + \
               onek_encoding_unk(int(atom.GetTotalNumHs()), ATOM_FEATURES['num_Hs']) + \
               onek_encoding_unk(int(atom.GetHybridization()), ATOM_FEATURES['hybridization']) + \
               [1 if atom.GetIsAromatic() else 0] + \
               [atom.GetMass() * 0.01]  # scaled to about the same range as other features
    if functional_groups is not None:
        features += functional_groups
    return np.array(features, dtype=np.float32)

def bond_features(bond: Chem.rdchem.Bond):
    """
    Builds a feature vector for a bond.

    :param bond: A RDKit bond.
    :return: A list containing the bond features.
    """
    if bond is None:
        fbond = [1] + [0] * (BOND_FDIM - 1)
    else:
        bt = bond.GetBondType()
        fbond = [
            0,  # bond is not None
            bt == Chem.rdchem.BondType.SINGLE,
            bt == Chem.rdchem.BondType.DOUBLE,
            bt == Chem.rdchem.BondType.TRIPLE,
            bt == Chem.rdchem.BondType.AROMATIC,
            (bond.GetIsConjugated() if bt is not None else 0),
            (bond.IsInRing() if bt is not None else 0)
        ]
        fbond += onek_encoding_unk(int(bond.GetStereo()), list(range(6)))
    return np.array(fbond, dtype=np.float32)

def get_dgl_graph(smiles, add_edge_data=False):
    """
       Computes the graph structure and featurization of a molecule.

       :param smiles: A smiles string.
       :param args: Arguments.
       """
    g = dgl.DGLGraph()

    # Convert smiles to molecule
    mol = Chem.MolFromSmiles(smiles)
    if mol is None:
        return None
    # fake the number of "atoms" if we are collapsing substructures
    n_atoms = mol.GetNumAtoms()

    for i, atom in enumerate(mol.GetAtoms()):
        g.add_nodes(1, data={'atom_features': torch.from_numpy(atom_features(atom)).view(1, -1)})

    for a1 in range(n_atoms):
        for a2 in range(a1 + 1, n_atoms):
            bond = mol.GetBondBetweenAtoms(a1, a2)
            if bond is None:
                continue

            if add_edge_data:
                f_bond = bond_features(bond)
                d = {'edge_features': torch.from_numpy(f_bond).view(1, -1)}
                g.add_edge(a1, a2, data=d)
                g.add_edge(a2, a1, data=d)
            else:
                g.add_edge(a1, a2)
                g.add_edge(a2, a1)
    return g

def get_dgl_graph_batch(smiles, size, add_edge_data=False):
    """
       Computes the graph structure and featurization of a molecule.

       :param smiles: A smiles string.
       :param args: Arguments.
       """
    gs = [dgl.DGLGraph() for i in range(size)]

    # Convert smiles to molecule
    mol = Chem.MolFromSmiles(smiles)
    if mol is None:
        return None
    # fake the number of "atoms" if we are collapsing substructures
    n_atoms = mol.GetNumAtoms()

    for i, atom in enumerate(mol.GetAtoms()):
        ats = atom_features(atom)
        data = {'atom_features': torch.from_numpy(ats).view(1, -1)}
        for g in gs:
            g.add_nodes(1, data=data)

    for a1 in range(n_atoms):
        for a2 in range(a1 + 1, n_atoms):
            bond = mol.GetBondBetweenAtoms(a1, a2)
            if bond is None:
                continue

            if add_edge_data:
                f_bond = bond_features(bond)
                d = {'edge_features': torch.from_numpy(f_bond).view(1, -1)}
                for g in gs:
                    g.add_edge(a1, a2, data=d)
                    g.add_edge(a2, a1, data=d)
            else:
                for g in gs:
                    g.add_edge(a1, a2)
                    g.add_edge(a2, a1)
    return gs

def interpolate_points(x, y, sampling):
    ln = LinearRegression()
    data = np.stack((x, y))
    data_train = np.array([0, 1]).reshape(-1, 1)
    ln.fit(data_train, data)

    return ln.predict(sampling.reshape(-1, 1)).astype(np.float32)

def adjust_learning_rate(args, optimizer, epoch, step, len_epoch):
    """LR schedule that should yield 76% converged accuracy with batch size 256"""
    factor = epoch // 30

    if epoch >= 80:
        factor = factor + 1

    lr = args.lr * (0.1 ** factor)

    """Warmup"""
    if epoch < 5:
        lr = lr * float(1 + step + epoch * len_epoch) / (5. * len_epoch)

    if (args.local_rank == 0):
        print("epoch = {}, step = {}, lr = {}".format(epoch, step, lr))

    for param_group in optimizer.param_groups:
        param_group['lr'] = lr

def save_checkpoint(state, is_best, filename='checkpoint.pth.tar'):
    torch.save(state, filename)
    if is_best:
        shutil.copyfile(filename, 'model_best.pth.tar')

def reduce_tensor(args, tensor):
    rt = tensor.clone()
    dist.all_reduce(rt, op=dist.reduce_op.SUM)
    rt /= args.world_size
    return rt

class AverageMeter(object):
    """Computes and stores the average and current value"""

    def __init__(self):
        self.reset()

    def reset(self):
        self.val = 0
        self.avg = 0
        self.sum = 0
        self.count = 0

    def update(self, val, n=1):
        self.val = val
        self.sum += val * n
        self.count += n
        self.avg = self.sum / self.count

class Invert(object):
    """Inverts the color channels of an PIL Image
    while leaving intact the alpha channel.
    """

    def invert(self, img):
        r"""Invert the input PIL Image.
        Args:
            img (PIL Image): Image to be inverted.
        Returns:
            PIL Image: Inverted image.
        """
        if not F._is_pil_image(img):
            raise TypeError('img should be PIL Image. Got {}'.format(type(img)))

        if img.mode == 'RGBA':
            r, g, b, a = img.split()
            rgb = Image.merge('RGB', (r, g, b))
            inv = ImageOps.invert(rgb)
            r, g, b = inv.split()
            inv = Image.merge('RGBA', (r, g, b, a))
        elif img.mode == 'LA':
            l, a = img.split()
            l = ImageOps.invert(l)
            inv = Image.merge('LA', (l, a))
        else:
            inv = ImageOps.invert(img)
        return inv

    def __call__(self, img):
        """
        Args:
            img (PIL Image): Image to be inverted.
        Returns:
            PIL Image: Inverted image.
        """
        return self.invert(img)

    def __repr__(self):
        return self.__class__.__name__ + '()'


import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.distributions import Categorical
from networks import Value, Actor
from utils import ReplayBuffer

class Agent:
	def __init__(self, alpha, beta, input_shape, n_actions, batch_size=64, gamma=0.99,
				ent_weight=0.01, eps=0.2, fc1_dims=256, fc2_dims=256):
		self.input_shape = input_shape
		self.n_actions = n_actions
		self.batch_size = batch_size
		self.gamma = gamma
		self.ent_weight = ent_weight
		self.eps = eps
		self.fc1_dims = fc1_dims

		self.value = Value(beta, input_shape, fc1_dims, fc2_dims, n_actions)
		self.actor = Actor(alpha, input_shape, fc1_dims, fc2_dims, n_actions)
		self.memory = ReplayBuffer()

	def store_transition(self, state, action, reward, state_, done):
		self.memory.store_transition(state, action, reward, state_, done)

	def choose_action(self, state):
		state = torch.tensor([state], dtype=torch.float).to(self.actor.device)
		probs = self.actor(state)
		dist = Categorical(probs)
		action = dist.sample()
		log_prob = dist.log_prob(action).detach()

		return action.detach().item(), log_prob

	def calc_rewards_to_go(self, rewards, is_terminals, gamma, final_state_value):
		rewards_to_go = []
		discounted_reward = final_state_value

		# accumulate rewards starting from the end of the buffer, working backwards
		for reward, done in zip(reversed(rewards), reversed(is_terminals)):
			if done: # reset to zero for terminal states
				discounted_reward = 0
			discounted_reward = reward + gamma * discounted_reward
			rewards_to_go.append(discounted_reward)
		return list(reversed(rewards_to_go)) # finally, reverse again to make forward-ordered

	def evaluate(self, states, actions):
		probs = self.actor(states)
		dist = Categorical(probs)
		action_log_probs = dist.log_prob(actions).to(self.actor.device)
		state_values = self.value(states).to(self.actor.device)

		return action_log_probs, torch.squeeze(state_values), dist.entropy()

	def learn(self, pi_update_iter, value_update_iter, new_state, done):
		print("Learning update")

		# calculate rewards to go
		final_state_value = 0 if done else self.value(torch.tensor([new_state], dtype=torch.float32).to(self.actor.device)).item()
		rewards_to_go = self.calc_rewards_to_go(self.memory.rewards, self.memory.is_terminals, self.gamma, final_state_value)

		# convert to torch tensor and normalize
		rewards_to_go = torch.tensor(rewards_to_go, dtype=torch.float32).to(self.actor.device)
		rewards_to_go = (rewards_to_go - rewards_to_go.mean()) / rewards_to_go.std()

		old_states = torch.tensor(self.memory.states, dtype=torch.float32).to(self.actor.device)
		old_actions = torch.tensor(self.memory.actions, dtype=torch.float32).to(self.actor.device)
		old_log_probs = torch.tensor(self.memory.log_probs, dtype=torch.float32).to(self.actor.device).detach()

		# evaluate a new policy at the old transitions and update actor params
		for _ in range(pi_update_iter):
			self.actor.optimizer.zero_grad()
			log_probs, state_values, entropy_bonus = self.evaluate(old_states, old_actions)
			ratios = torch.exp(log_probs - old_log_probs)
			clipped_ratios = torch.clamp(ratios, 1-self.eps, 1+self.eps)

			# calculate advantage function
			state_values = state_values.detach()
			advantages = rewards_to_go - state_values

			surr1 = ratios * advantages
			surr2 = clipped_ratios * advantages

			actor_loss = -torch.min(surr1, surr2).mean() - self.ent_weight * entropy_bonus.mean()
			actor_loss.backward()
			self.actor.optimizer.step()

		# minimize MSE loss between state_values and rewards_to_go
		for _ in range(value_update_iter):
			self.value.optimizer.zero_grad()
			_, state_values, _ = self.evaluate(old_states, old_actions)

			value_loss = F.mse_loss(state_values, rewards_to_go)
			value_loss.backward()
			self.value.optimizer.step()

		self.memory.clear() # clear replay buffer after learning update

	def save_models(self):
		self.actor.save_checkpoint()
		self.value.save_checkpoint()

	def load_models(self):
		self.actor.load_checkpoint()
		self.value.load_checkpoint()


import pygame, sys, time
from pygame.locals import *

# Pygame installation.
pygame.init()

# Window setting.
WINDOWWIDTH = 400
WINDOWHEIGHT = 400
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
pygame.display.set_caption('Animation')

# Variables of direction.
DOWNLEFT = 'downleft'
DOWNRIGHT = 'downright'
UPLEFT = 'upleft'
UPRIGHT = 'upright'

MOVESPEED = 4

# Color setting.
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

# Data structure.
b1 = {'rect': pygame.Rect(300, 80, 50, 100), 'color':RED, 'dir':UPRIGHT}
b2 = {'rect': pygame.Rect(200, 200, 20, 20), 'color':GREEN, 'dir':UPLEFT}
b3 = {'rect': pygame.Rect(100, 1500, 60, 60), 'color':BLUE, 'dir':DOWNLEFT}
boxes = [b1, b2, b3]

# First game cycle start.
while True:
	# Check of QUIT event.
	for event in pygame.event.get():
		if event.type == QUIT:
			pygame.quit()
			sys.exit()

	# Creating white background.
	windowSurface.fill(WHITE)

	for b in boxes:
		# Moving data structure.
		if b['dir'] == DOWNLEFT:
			b['rect'].left -= MOVESPEED
			b['rect'].top += MOVESPEED
		if b['dir'] == DOWNRIGHT:
			b['rect'].left += MOVESPEED
			b['rect'].top += MOVESPEED
		if b['dir'] == UPLEFT:
			b['rect'].left -= MOVESPEED
			b['rect'].top -= MOVESPEED
		if b['dir'] == UPRIGHT:
			b['rect'].left += MOVESPEED
			b['rect'].top -= MOVESPEED

	# Check if the block touches window border.
		if b['rect'].top < 0:
			# Upper border.
			if b['dir'] == UPLEFT:
				b['dir'] = DOWNLEFT
			if b['dir'] == UPRIGHT:
				b['dir'] = DOWNRIGHT
		if b['rect'].bottom > WINDOWHEIGHT:
			# Lower border.
			if b['dir'] == DOWNLEFT:
				b['dir'] == UPLEFT
			if b['dir'] == DOWNRIGHT:
				b['dir'] = UPRIGHT
		if b['rect'].left < 0:
			# Left border.
			if b['dir'] == DOWNLEFT:
				b['dir'] = DOWNRIGHT
			if b['dir'] == UPLEFT:
				b['dir'] = UPRIGHT
		if b['rect'].right > WINDOWWIDTH:
			# Right border.
			if b['dir'] == DOWNRIGHT:
				b['dir'] = DOWNLEFT
			if b['dir'] == UPRIGHT:
				b['dir'] = UPLEFT

		# Create block on the surface.
		pygame.draw.rect(windowSurface, b['color'], b['rect'])

	# Display.
	pygame.display.update()
	time.sleep(0.02)


from decouple import config
from django.conf import settings
from django.core.mail import send_mail
from django.shortcuts import render, redirect
from django.urls import reverse
from django.views import View
from .forms import ContactForm

class ContactView(View):
    template_name = "contact/contact.html"

    def get(self, request):
        form = ContactForm()
        return render(request, self.template_name, {"form": form})

    def post(self, request):
        form = ContactForm(request.POST)
        if form.is_valid():
            # contact = form.save()
            print()
            print(request.POST["fullname"])
            print(request.POST["email"])
            print(request.POST["message"])
            print()

            send_mail(
                # Subject
                f"New Contact Form Message from, {request.POST['fullname']}",
                # Content
                request.POST["message"],
                # Sender's email
                config("SEND_TO"),
                # Recipient(s)
                ["dkibui@outlook.com"],
                fail_silently=False,
            )

            return redirect(reverse("contact:index"))
        return render(request, self.template_name, {"form": form})


## ni.duman
import numpy as np
import matplotlib.pyplot as plt
import random
import math

# fonkisyonu tanımlama
def f(x):
    x1 = x[0]
    x2 = x[1]
    obj = (1 + (x1 + x2 + 1)**2 * (19 - 14*x1 + 3*(x1**2) - 14*x2 + 6*x1*x2 + 3*(x2**2))) * (30 + (2*x1 - 3*x2)**2 * (18 - 32*x1 + 12*(x1**2) + 48*x2 - 36*x1*x2 + 27*(x2**2)))
    return obj

# aralık
x_start = [0.8, -0.5]

# Simulated Kodu

# Düngü sayısı
n = 30
# Döngü başına deneme sayısı
m = 75

na = 0.0
# en kötü çözüm başlangıç
p1 = 0.7
# En kötü çözüm bitiş
p50 = 0.001
# başlangıç sıcaklığı
t1 = -1.0/math.log(p1)
# final sıcaklığı
t50 = -1.0/math.log(p50)

frac = (t50/t1)**(1.0/(n-1.0))

x = np.zeros((n+1,2))
x[0] = x_start
xi = np.zeros(2)
xi = x_start
na = na + 1.0
# Anlık sonuçlar
xc = np.zeros(2)
xc = x[0]
fc = f(xi)
fs = np.zeros(n+1)
fs[0] = fc
# Anlık sıcaklık
t = t1
# Ortalama Sıcaklık
DeltaE_avg = 0.0
for i in range(n):
    print('Döngü: ' + str(i) + ' nin sıcaklığı: ' + str(t))
    for j in range(m):
        # yeni noktalar
        xi[0] = xc[0] + random.random() - 0.5
        xi[1] = xc[1] + random.random() - 0.5
        # alt üst sıçrama
        xi[0] = max(min(xi[0],2.0),-2.0)
        xi[1] = max(min(xi[1],2.0),-2.0)
        DeltaE = abs(f(xi)-fc)
        if (f(xi)>fc):
            # ilk iterasyonda daha kötü bir ortalama bulduysa          #   on the first iteration
            if (i==0 and j==0): DeltaE_avg = DeltaE

            # kabul  fonksiyonu

            p = math.exp(-DeltaE/(DeltaE_avg * t))
            # kötü çözümü edip etmemeyi kararlaştırma
            if (random.random()<p):
                # kabu etme
                accept = True
            else:
                # kabul etmeme
                accept = False
        else:
            # otomatik kabul etme
            accept = True
        if (accept==True):
            # anlık durumu güncelleme
            xc[0] = xi[0]
            xc[1] = xi[1]
            fc = f(xc)
            # kabul edilen çözüm sayısını ve delta yı arttırma arttırma
            na = na + 1.0
            DeltaE_avg = (DeltaE_avg * (na-1.0) +  DeltaE) / na
    # En iyi x değerlerini saklama
    x[i+1][0] = xc[0]
    x[i+1][1] = xc[1]
    fs[i+1] = fc
    # Sıradaki döngü için sıcaklığı azalta
    t = frac * t

# ekrana yazdırma
print('En iyi çözüm: ' + str(xc))
print('En iyi hedef: ' + str(fc))

"""plt.plot(x[:,0],x[:,1],'y-o')
plt.savefig('contour.png')"""

fig = plt.figure()
ax1 = fig.add_subplot(211)
ax1.plot(fs,'r.-')
ax1.legend(['Objective'])
ax2 = fig.add_subplot(212)
ax2.plot(x[:,0],'b.-')
ax2.plot(x[:,1],'g--')
ax2.legend(['x1','x2'])

# PNG olarak saklama
plt.savefig('iterations.png')

plt.show()


import math
import scipy.signal as signal
import numpy as np
import bisect

class vertexLocator:
  def __init__(self, disk1, disk2, n1, n2):
    self.id1 = n1
    self.id2 = n2
    self.pos_sideRadii1 = self.filterHits(disk1, n1)
    self.pos_sideRadii2 = self.filterHits(disk2, n2)
    self.neg_sideRadii1 = self.filterHits(disk1, -n1)
    self.neg_sideRadii2 = self.filterHits(disk2, -n2)

    #print "self.pos_sideRadii1", self.pos_sideRadii1
    #print "self.pos_sideRadii2", self.pos_sideRadii2
    #print "self.neg_sideRadii1", self.neg_sideRadii1
    #print "self.neg_sideRadii2", self.neg_sideRadii2

  def getDiskEnvelope(self, n):
    nabs = abs(n)
    sgn = nabs/n
    if (nabs == 1):
      return (sgn*300., 30., 150.)
    elif (nabs == 2):
      return (sgn*400., 30., 150.)
    elif (nabs == 3):
      return (sgn*500., 30., 150.)
    elif (nabs == 4):
      return (sgn*650., 30., 150.)
    elif (nabs == 5):
      return (sgn*850., 30., 150.)
    elif (nabs == 6):
      return (sgn*1100., 30., 150.)
    elif (nabs == 7):
      return (sgn*1400., 30., 150.)
    elif (nabs == 8):
      return (sgn*2000., 100., 150.)
    elif (nabs == 9):
      return (sgn*2300., 100., 150.)
    elif (nabs == 10):
      return (sgn*2650., 100., 150.)
    else:
      return (0.,0.,0.)

  def filterHits(self,disk,iddisk):
    (z, rmin, rmax) = self.getDiskEnvelope(iddisk)
    hits = []
    for track in disk:
      if abs(track.ZOuter - z) < 5 : #mm
        r = math.sqrt(track.XOuter**2+track.YOuter**2)
        phi = math.atan2(track.YOuter,track.XOuter)
        if (r > rmin and r < rmax):
          hits.append((r,phi))
    #sort by phi
    hits.sort(key=lambda hit: hit[1])
    return hits

  def vertices(self, ntracks):
    z0sPlus = self.make_pairs(self.pos_sideRadii1, self.id1, self.pos_sideRadii2, self.id2)
    z0sMinus = self.make_pairs(self.neg_sideRadii1, self.id1, self.neg_sideRadii2, self.id2)

    z0s = []
    z0s.extend(z0sPlus)
    z0s.extend(z0sMinus)
    #print "z0s ", z0s
    bins=np.arange(-100,100,1)
    h,bin_edges = np.histogram(z0s, bins=bins)
    #print "h", h
    median = np.median(h)
    all_maxima = signal.find_peaks_cwt(h, np.arange(0.5,1))
    the_vertices = []
    for i in all_maxima:
      if h[i] >= ntracks:
        the_vertices.append((bin_edges[i]+bin_edges[i+1])/2.)

    #print the_vertices
    return the_vertices

  def make_pairs(self, r1s, id1, r2s, id2):
    z1 = self.getDiskEnvelope(id1)[0]
    z2 = self.getDiskEnvelope(id2)[0]
    z0s = []
    if (len(r1s)>1 and len(r2s)>1):
      for r1,phi1 in r1s:
        #get close hits in phi in the other disk
        keys = [rp[1] for rp in r2s]
        minimum = phi1-10*math.pi/180 if phi1-10*math.pi/180. > -math.pi else 2*math.pi+phi1-10*math.pi/180.
        maximum = phi1+10*math.pi/180 if phi1+10*math.pi/180. < math.pi else phi1+10*math.pi/180. -2*math.pi
        if maximum < minimum:
          tmp = maximum
          maximum = minimum
          minimum = tmp
        start = bisect.bisect_left(keys,minimum)
        stop = bisect.bisect_left(keys,maximum)
        secondDiskHits = r2s[start:stop]
        #print "phi1 is",phi1," propagating to", secondDiskHits
        for r2,phi2 in secondDiskHits:
          m = (z2-z1)/(r2-r1)
          z0 = -m*r1+z1
          z0s.append(z0)

    return z0s