from neural_net import NeuralNetwork, NetworkFramework
from neural_net import Node, Target, Input
import random
import math
import py.test

INPUT = 1
HIDDEN = 2
OUTPUT = 3

# <--- Problem 3, Question 1 --->

def FeedForward(network, input):
  """
  Arguments:
  ---------
  network : a NeuralNetwork instance
  input   : an Input instance

  Returns:
  --------
  Nothing

  Description:
  -----------
  This function propagates the inputs through the network. That is,
  it modifies the *raw_value* and *transformed_value* attributes of the
  nodes in the network, starting from the input nodes.

  Notes:
  -----
  The *input* arguments is an instance of Input, and contains just one
  attribute, *values*, which is a list of pixel values. The list is the
  same length as the number of input nodes in the network.

  i.e: len(input.values) == len(network.inputs)

  This is a distributed input encoding (see lecture notes 7 for more
  informations on encoding)

  In particular, you should initialize the input nodes using these input
  values:

  network.inputs[i].raw_value = input[i] # This is wrong
  """
  network.CheckComplete()

  # Propagation helper; takes hidden and output nodes
  def propagate(nodes):
    for n in nodes:
      # Compute raw value
      n.raw_value = network.ComputeRawValue(n)
      # Compute transformed value
      n.transformed_value = network.Sigmoid(n.raw_value)

  # Assign input values to input nodes
  for i in xrange(len(input.values)):
    network.inputs[i].raw_value = input.values[i]
    network.inputs[i].transformed_value = input.values[i]

  propagate(network.hidden_nodes + network.outputs)

#< --- Problem 3, Question 2

def Backprop(network, input, target, learning_rate):
  """
  Arguments:
  ---------
  network       : a NeuralNetwork instance
  input         : an Input instance
  target        : a target instance
  learning_rate : the learning rate (a float)

  Returns:
  -------
  Nothing

  Description:
  -----------
  The function first propagates the inputs through the network
  using the Feedforward function, then backtracks and update the
  weights.

  Notes:
  ------
  The remarks made for *FeedForward* hold here too.

  The *target* argument is an instance of the class *Target* and
  has one attribute, *values*, which has the same length as the
  number of output nodes in the network.

  i.e: len(target.values) == len(network.outputs)

  In the distributed output encoding scenario, the target.values
  list has 10 elements.

  When computing the error of the output node, you should consider
  that for each output node, the target (that is, the true output)
  is target[i], and the predicted output is network.outputs[i].transformed_value.
  In particular, the error should be a function of:

  target[i] - network.outputs[i].transformed_value

  """
  network.CheckComplete()

  # First propagate the input through the network
  FeedForward(network, input)

  # Calculate output errors and deltas
  for (y,out_node) in zip(target.values, network.outputs):
    out_node.error = y - out_node.transformed_value
    out_node.delta = out_node.error * network.SigmoidPrime(out_node.raw_value)

  # Backpropagate in reverse topoligical order
  nodes = network.inputs + network.hidden_nodes
  nodes.reverse()

  for node in nodes:
    node.error = 0.
    for child,w in zip(node.forward_neighbors, node.forward_weights):
      if node.inputs:
        node.error += w.value * child.delta
      w.value += learning_rate * node.transformed_value * child.delta
    if node.inputs:
      node.delta = node.error * network.SigmoidPrime(node.raw_value)
      node.fixed_weight.value += learning_rate * node.delta

# <--- Problem 3, Question 3 --->

def Train(network, inputs, targets, learning_rate, epochs):
  """
  Arguments:
  ---------
  network       : a NeuralNetwork instance
  inputs        : a list of Input instances
  targets       : a list of Target instances
  learning_rate : a learning_rate (a float)
  epochs        : a number of epochs (an integer)

  Returns:
  -------
  Nothing

  Description:
  -----------
  This function should train the network for a given number of epochs. That is,
  run the *Backprop* over the training set *epochs*-times
  """
  network.CheckComplete()
  for _ in xrange(epochs):
    for input,target in zip(inputs, targets):
      Backprop(network, input, target, learning_rate)

# <--- Problem 3, Question 4 --->

class EncodedNetworkFramework(NetworkFramework):
  def __init__(self):
    """
    Initializatio.
    YOU DO NOT NEED TO MODIFY THIS __init__ method
    """
    super(EncodedNetworkFramework, self).__init__() # < Don't remove this line >

  # <--- Fill in the methods below --->

  def EncodeLabel(self, label):
    """
    Arguments:
    ---------
    label: a number between 0 and 9

    Returns:
    ---------
    a list of length 10 representing the distributed
    encoding of the output.

    Description:
    -----------
    Computes the distributed encoding of a given label.

    Example:
    -------
    0 => [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    3 => [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

    Notes:
    ----
    Make sure that the elements of the encoding are floats.

    """
    target = Target()
    target.values = [1.0 if i == label else 0.0 for i in xrange(10)]
    return target

  def GetNetworkLabel(self):
    """
    Arguments:
    ---------
    Nothing

    Returns:
    -------
    the 'best matching' label corresponding to the current output encoding

    Description:
    -----------
    The function looks for the transformed_value of each output, then decides
    which label to attribute to this list of outputs. The idea is to 'line up'
    the outputs, and consider that the label is the index of the output with the
    highest *transformed_value* attribute

    Example:
    -------

    # Imagine that we have:
    map(lambda node: node.transformed_value, self.network.outputs) => [0.2, 0.1, 0.01, 0.7, 0.23, 0.31, 0, 0, 0, 0.1, 0]

    # Then the returned value (i.e, the label) should be the index of the item 0.7,
    # which is 3

    """
    transformed_values = map(lambda n: n.transformed_value, self.network.outputs)
    return transformed_values.index(max(transformed_values))

  def Convert(self, image):
    """
    Arguments:
    ---------
    image: an Image instance

    Returns:
    -------
    an instance of Input

    Description:
    -----------
    The *image* arguments has 2 attributes: *label* which indicates
    the digit represented by the image, and *pixels* a matrix 14 x 14
    represented by a list (first list is the first row, second list the
    second row, ... ), containing numbers whose values are comprised
    between 0 and 256.0. The function transforms this into a unique list
    of 14 x 14 items, with normalized values (that is, the maximum possible
    value should be 1).

    """
    input = Input()
    input.values = [item/256. for sublist in image.pixels for item in sublist]
    return input

  def InitializeWeights(self):
    """
    Arguments:
    ---------
    Nothing

    Returns:
    -------
    Nothing

    Description:
    -----------
    Initializes the weights with random values between [-0.01, 0.01].

    Hint:
    -----
    Consider the *random* module. You may use the the *weights* attribute
    of self.network.

    """
    for weight in self.network.weights:
      weight.value = random.uniform(-.01,.01)

#<--- Problem 3, Question 6 --->

class SimpleNetwork(EncodedNetworkFramework):
  def __init__(self):
    """
    Arguments:
    ---------
    Nothing

    Returns:
    -------
    Nothing

    Description:
    -----------
    Initializes a simple network, with 196 input nodes,
    10 output nodes, and NO hidden nodes. Each input node
    should be connected to every output node.
    """
    super(SimpleNetwork, self).__init__() # < Don't remove this line >

    # 1) Adds an input node for each pixel.
    network = self.network
    for _ in xrange(196): # 196 = 14*14
      network.AddNode(Node(), INPUT)

    # 2) Add an output node for each possible digit label.
    for _ in xrange(10):
      node = Node()
      for input_node in network.inputs:
        node.AddInput(input_node, None, network)
      network.AddNode(node, OUTPUT)

#<---- Problem 3, Question 7 --->

class HiddenNetwork(EncodedNetworkFramework):
  def __init__(self, number_of_hidden_nodes=15):
    """
    Arguments:
    ---------
    number_of_hidden_nodes : the number of hidden nodes to create (an integer)

    Returns:
    -------
    Nothing

    Description:
    -----------
    Initializes a network with a hidden layer. The network
    should have 196 input nodes, the specified number of
    hidden nodes, and 10 output nodes. The network should be,
    again, fully connected. That is, each input node is connected
    to every hidden node, and each hidden_node is connected to
    every output node.
    """
    super(HiddenNetwork, self).__init__() # < Don't remove this line >

    # 1) Adds an input node for each pixel
    network = self.network
    for _ in xrange(196): # 196 = 14*14
      network.AddNode(Node(), INPUT)

    # 2) Adds the hidden layer
    for _ in xrange(number_of_hidden_nodes):
      node = Node()
      for input_node in network.inputs:
        node.AddInput(input_node, None, network)
      network.AddNode(node, HIDDEN)

    # 3) Adds an output node for each possible digit label.
    for _ in xrange(10):
      node = Node()
      for hidden_node in network.hidden_nodes:
        node.AddInput(hidden_node, None, network)
      network.AddNode(node, OUTPUT)

#<--- Problem 3, Question 8 --->

class CustomNetwork(EncodedNetworkFramework):
  def __init__(self, hidden_num=15, prob=0.8):
    """
    Arguments:
    ---------
    Your pick.

    Returns:
    --------
    Your pick

    Description:
    -----------
    Surprise me!
    """
    super(CustomNetwork, self).__init__() # <Don't remove this line>

    network = self.network
    for _ in xrange(196): # 196 = 14*14
      network.AddNode(Node(), INPUT)

    for _ in xrange(hidden_num):
      node = Node()
      for input_node in network.inputs:
        if random.random() < prob:
          node.AddInput(input_node, None, network)
      network.AddNode(node, HIDDEN)

    for _ in xrange(10):
      node = Node()
      for hidden_node in network.hidden_nodes:
        node.AddInput(hidden_node, None, network)
      network.AddNode(node, OUTPUT)


# Challenge: Find the Shortest Path Between Two Vertices

from lesson0 import Graph
from stacks import MyStack
# You can check the input graph in console tab
min_distance = 999999999

def dfs(g, source, destination, visited, distance=0):
    global min_distance
    visited[source] = True
    if source == destination:
        min_distance = min(distance, min_distance)
    adjacent = g.array[source].head_node
    while adjacent:
        if not visited[adjacent.data]:
            dfs(g, source=adjacent.data, destination=destination,
                visited=visited, distance=distance+1)
        adjacent = adjacent.next_element

def find_min(g, source, destination):
    # Write your code here
    if source == destination:
        return 0
    visited = [False]*g.vertices
    dfs(g, source, destination, visited)
    return -1 if min_distance == 999999999 else min_distance

if __name__ == "__main__":

    g = Graph(5)
    g.add_edge(0, 1)
    g.add_edge(0, 2)
    g.add_edge(0, 3)
    g.add_edge(3, 5)
    g.add_edge(2, 4)
    g.add_edge(5, 4)

    print(find_min(g, 0, 4))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Jan 11 15:52:40 2018
@author: acabbia
"""

import cobra
import GEOparse
from tissuespecific.reconstruction import Builder

#set paths
path = '/home/acabbia/Documents/Muscle_Model/models'
ref_model_path = path + '/recon2.2.xml'
library_folder =  path + '/library_GEOmerge/'
#Gene expression data GEO ID (Raue 2012)
GEO_accession_list = ['GSE9103','GSE25941','GSE28422','GSE47881']

def  build_models_library(ref_model_path, GEO_accession_nr,requirements, expr_cutoff, library_folder):
    # import reference model (RECON2.2)
    recon22 = cobra.io.read_sbml_model(ref_model_path)
    #get data from GEO
    serie=GEOparse.get_GEO(geo=GEO_accession_nr)
    #build translator dict
    table =  serie.gsms[list(serie.gsms.keys())[0]].table
    translator = Builder.affyprobe_translator(table, 'hgnc_id')

    #################################################################################################################
    # main loop builds model for each subject in serie
    print('===============================')
    for gsm in serie.gsms:
        label = str(serie.gsms[gsm].metadata['title']).split('_')
        print('Building model '+ 'ASK_'+label[1][0]+label[2][0]+'_'+gsm[-2:])
        eset = serie.gsms[gsm].table
        confidence = Builder.rxn_confidence(recon22, eset, translator,'hgnc_id', expr_cutoff )
        for r_id in requirements:
            confidence[r_id] = 3
        newmodel = Builder.build_model(recon22,confidence)
        newmodel.name = 'Aging Skeletal Muscle '+ gsm + label[1]+label[2]

        # Reactions to be corrected (h_i)
        newmodel.reactions.CYOOm3.add_metabolites({'h_m':-7.9,'h_i':4 ,'h_c':0}, combine=False)
        # Fix PDH reversibility/directionality
        newmodel.reactions.PDHm.bounds = 0, 1000
        #prune unused metabolites
        remov = cobra.manipulation.delete.prune_unused_metabolites(newmodel)
        while len(remov) != 0:
            remov = cobra.manipulation.delete.prune_unused_metabolites(newmodel)
        #write newmodel in SBML
        cobra.io.write_sbml_model(newmodel,filename= library_folder+'ASK_'+label[1][0]+label[2][0]+'_'+gsm[-2:]+'.xml')
        print('===============================')

    ###############################################################################################################


#!/usr/bin/env python

import sys
import numpy
import os
from podi_definitions import *
import astropy.io.fits as pyfits
import datetime
import scipy
import scipy.stats
import scipy.ndimage

from astLib import astWCS

import matplotlib.pyplot as plot

filename = sys.argv[1]
hdulist = pyfits.open(filename)

inputhdu = hdulist['OTA61.SCI']

img = inputhdu.data.T

# figure out the maximum extensions of the input frame
wcs = astWCS.WCS(inputhdu.header, mode="pyfits")

def fill_entries(hdr, ordering, keyformat):
    retarray = numpy.zeros(shape=ordering.shape)
    for y in range(retarray.shape[0]):
        for x in range(retarray.shape[1]):
            keyname = keyformat % (ordering[y,x])
            try:
                #retarray[y,x] = ordering[y,x] #hdr[keyname]
                retarray[y,x] = hdr[keyname]
            except:
                pass
    return retarray

def header_to_polynomial(hdr):

    xi = numpy.zeros(shape=(6,6))
    xi_r = numpy.zeros(shape=(1,6))

    eta = numpy.zeros(shape=(6,6))
    eta_r = numpy.zeros(shape=(1,6))

    ordering = numpy.array([
        [ 0,  1,  4,  7, 12, 17],
        [ 2,  5,  8, 13, 18, -1],
        [ 6,  9, 14, 19, -1, -1],
        [10, 15, 20, -1, -1, -1],
        [16, 21, -1, -1, -1, -1],
        [22, -1, -1, -1, -1, -1]
        ])
    ordering_r = numpy.array([
            [-1, 3, 11, -1, 23]
            ])

    xi = fill_entries(hdr, ordering, "PV1_%d")
    xi_r = fill_entries(hdr, ordering_r, "PV1_%d")
    eta = fill_entries(hdr, ordering, "PV2_%d")
    eta_r = fill_entries(hdr, ordering_r, "PV2_%d")

    if (not 'PV1_1' in hdr):  xi[0,1] = 1.0
    if (not 'PV2_1' in hdr): eta[0,1] = 1.0

    cd = numpy.zeros(shape=(2,2))
    if ('CD1_1' in hdr): cd[0,0] = hdr['CD1_1']
    if ('CD1_2' in hdr): cd[0,1] = hdr['CD1_2']
    if ('CD2_1' in hdr): cd[1,0] = hdr['CD2_1']
    if ('CD2_2' in hdr): cd[1,1] = hdr['CD2_2']

    crval = numpy.zeros(shape=(2))
    if ('CRVAL1' in hdr): crval[0] = hdr['CRVAL1']
    if ('CRVAL2' in hdr): crval[1] = hdr['CRVAL2']

    crpix = numpy.zeros(shape=(2))
    if ('CRPIX1' in hdr): crpix[0] = hdr['CRPIX1']
    if ('CRPIX2' in hdr): crpix[1] = hdr['CRPIX2']

    return xi, xi_r, eta, eta_r, cd, crval, crpix

import itertools
def polyval2d(x, y, m):
    ij = itertools.product(range(m.shape[0]), range(m.shape[1]))
    z = numpy.zeros_like(x)
    for (i,j) in ij:
        #print i,j
        z += m[i,j] * x**j * y**i
        print(i, j, "-->", z)
    return z

def my_pix2wcs(xy, wcs_polynomials):

    c_xi, c_xi_r, c_eta, c_eta_r, cd, crval, crpix = wcs_polynomials

    #use the input x,y and compute xi and eta first

    print("crpix=", crpix)
    print("xy=\n", xy)
    xy_relative = xy[:,0:2] - crpix
    print("xy relative=\n", xy_relative)

    xi  = xy_relative[:,0] * cd[0,0] + xy_relative[:,1] * cd[0,1]
    eta = xy_relative[:,1] * cd[1,0] + xy_relative[:,1] * cd[1,1]

    print("xi=\n", xi)
    print("eta=\n", eta)

    # compute r = sqrt(xi**2 + eta**2)
    r = numpy.hypot(xi, eta)
    print("r=\n", r)

    print("c_xi_r", c_xi_r)
    print("c_eta_r", c_eta_r)

    xi_prime = polyval2d(xi, eta, c_xi) \
        + numpy.polynomial.polynomial.polyval(r, c_xi_r[0])

    eta_prime = polyval2d(eta, xi, c_eta) \
        + numpy.polynomial.polynomial.polyval(r, c_eta_r[0])

    print("xi_prime=\n", xi_prime)
    print("eta_prime=\n", eta_prime)

    print("crval:", crval)
    output = numpy.zeros_like(xy) #xi.shape[0],2)
    output[:,0] = xi_prime
    output[:,1] = eta_prime
    output[:,0:2] += crval

    return output

print("running soem stupid testing")
ra, dec = wcs.pix2wcs(2000.0, 2000.0)
print()
var = ra, dec
x,y = wcs.wcs2pix(ra, dec)
print(x, y)

wcs.header['PV2_18'] = wcs.header['PV2_18'] #0 #100e6
wcs.updateFromHeader()
x,y = wcs.wcs2pix(ra, dec)
print(x, y)

minRA, maxRA, minDec, maxDec = wcs.getImageMinMaxWCSCoords()
print(minRA, maxRA)
print(minDec, maxDec)

xd, yd = 4000, 4000

pixelscale = 0.11 / 3600.

#output_data = numpy.zeros(shape=(4000,4000))

cosine_correction = math.cos(math.radians(inputhdu.header['CRVAL2']))
width = (maxRA - minRA) / pixelscale * cosine_correction
height = (maxDec - minDec) / pixelscale
print("\nnew size: %d x %d\n" % (width, height))

primhdu = pyfits.PrimaryHDU(data=numpy.zeros(shape=(width,height)))
# primhdu.header.update("CRPIX1", 0) #inputhdu.header['CRPIX1'])
# primhdu.header.update("CRPIX2", 0) #inputhdu.header['CRPIX2'])
# primhdu.header.update("CRVAL1", inputhdu.header['CRVAL1'])
# primhdu.header.update("CRVAL2", inputhdu.header['CRVAL2'])
# primhdu.header.update("CD1_1",  inputhdu.header['CD1_1'])
# primhdu.header.update("CD1_2",  inputhdu.header['CD1_2'])
# primhdu.header.update("CD2_1",  inputhdu.header['CD2_1'])
# primhdu.header.update("CD2_2",  inputhdu.header['CD2_2'])

primhdu.header.update("CRPIX1", 0.0)
primhdu.header.update("CRPIX2", 0.0)
primhdu.header.update("CRVAL1", 24.) #inputhdu.header['CRVAL1'])
primhdu.header.update("CRVAL2", 31.) #inputhdu.header['CRVAL2'])
primhdu.header.update("CD1_1", pixelscale)
primhdu.header.update("CD1_2", 0.0)
primhdu.header.update("CD2_1", 0.0)
primhdu.header.update("CD2_2", pixelscale)

primhdu.header.update("CUNIT1", 'deg')
primhdu.header.update("CUNIT2", 'deg')
primhdu.header.update("CTYPE1", 'RA---TAN')
primhdu.header.update("CTYPE2", 'DEC--TAN')
primhdu.header.update("EQUINOX", 2000.0)
primhdu.header.update("RADESYS", 'ICRS')

# Now use this preliminary coordiante system to
# compute the position of the reference pixel
print("Creating output Ra/Dec system")
outputwcs = astWCS.WCS(primhdu.header, mode="pyfits")

#wcs_polynomials = header_to_polynomial(inputhdu.header)
wcs_polynomials = header_to_polynomial(primhdu.header)
xi, xi_r, eta, eta_r, cd, crval, crpix = wcs_polynomials
print(xi)

print("==============================")
print("==============================")
print("==============================")
radec = my_pix2wcs(numpy.array([[2000.,1000.]]), wcs_polynomials)
print("my=", radec)
print("wcs=", outputwcs.pix2wcs(2000., 1000.))
print("==============================")
print("==============================")
print("==============================")

sys.exit(0)

# Now for each pixel in the output frame, determine the RA and DEC sky coordinates
print("Translating x/y to Ra/Dec")
y, x = numpy.indices(primhdu.data.shape)
#print x[:10,:10]

output_ra = x * (pixelscale / cosine_correction) + minRA
output_dec = y * pixelscale + minDec

# Compute the pixel coordiante of the reference pixel for the current wcs solution
outputwcs.header['CRPIX1'] = 0
outputwcs.header['CRPIX2'] = 0
outputwcs.updateFromHeader()
crpix_x, crpix_y = outputwcs.wcs2pix(output_ra[0,0], output_dec[0,0])
print(crpix_x, crpix_y)

outputwcs.header['CRPIX1'] = crpix_x * -1
outputwcs.header['CRPIX2'] = crpix_y * -1
primhdu.header['CRPIX1'] = crpix_x * -1
primhdu.header['CRPIX2'] = crpix_y * -1
outputwcs.updateFromHeader()

newtry = outputwcs.wcs2pix(output_ra[0,0], output_dec[0,0])
print(newtry)

# origin_ra, origin_dec = wcs.pix2wcs(0,0)
# # Now compute the pixel of the original reference in the new frame
# crpix_x, crpix_y = outputwcs.wcs2pix(origin_ra, origin_dec)
# print crpix_x, crpix_y
# outputwcs.header['CRPIX1'] = crpix_x * -1
# outputwcs.header['CRPIX2'] = crpix_y * -1
# primhdu.header['CRPIX1'] = crpix_x * -1
# primhdu.header['CRPIX2'] = crpix_y * -1
# outputwcs.updateFromHeader()
# newtry = outputwcs.wcs2pix(origin_ra, origin_dec)
# print newtry

print("============================")

#output_radec = numpy.empty(shape=(output_ra.shape[0], output_ra.shape[1], 2))
#output_radec[:,:,0] = output_ra
#output_radec[:,:,1] = output_dec

# Using the sky-coordinates, convert them into X/Y in the original frame

# xy_coords_in_inputframe = numpy.array(wcs.wcs2pix(output_RaDec[:,0].ravel(), output_RaDec[:,1].ravel()))

print("converting sky-coordinates of the new frame into pixel x/y from the old frame")
xy_coords_in_inputframe = numpy.array(wcs.wcs2pix(output_ra.ravel(), output_dec.ravel()))

print(xy_coords_in_inputframe)
print(xy_coords_in_inputframe.shape)

print("swapping axes to make things compatible with numpy")

yx_coords_in_inputframe = numpy.swapaxes(xy_coords_in_inputframe,0,1)
print(yx_coords_in_inputframe)

print("deprojecting")

deproject = scipy.ndimage.interpolation.map_coordinates(
    input=img, coordinates=numpy.swapaxes(xy_coords_in_inputframe,0,1),
    output=None, order=1, mode='constant',
    cval=0.0, prefilter=True)

print(deproject.shape)

print("converting image back to 2-d")
deprojected_2d = numpy.reshape(deproject, primhdu.data.shape)
print(deprojected_2d.shape)

print("Saving image back to fits")
primhdu.data = deprojected_2d

primhdu.writeto("deprojected.fits", overwrite=True)

sys.exit(0)

#outputRA, outputDec = numpy.indices((4000,4000))
outputRA, outputDec = numpy.indices((xd,yd))

print("computing output Ra/dec for each pixel")
outputDec = numpy.array(outputDec, dtype=numpy.float32) * pixelscale + minDec
outputRA = numpy.array(outputRA, dtype=numpy.float32) * pixelscale / numpy.cos(numpy.radians(outputDec)) + minRA

print(outputRA[:5, :5])
print(outputDec[:5, :5])

#pixelcoords = numpy.zeros((4000,4000,2))

print("converting ra/dec to x/y for each output pixel")

print(outputRA.ravel().shape)
#ret = wcs.pix2wcs(outputRA.ravel(), outputDec.ravel())
ret = wcs.wcs2pix(outputRA.ravel(), outputDec.ravel())
#print ret

retarray = numpy.array(ret)
print(retarray.shape)
print(retarray[0:10, :])
x = retarray[:,0]
y = retarray[:,1]

#xy_2d = numpy.reshape(retarray, (500,500,2))
#print xy_2d[0,0:10,:]

#print x[:10]
#print y[:10]

print("deprojecting")

#deproject1 = scipy.ndimage.interpolation.map_coordinates(input=img, coordinates=[[5,5],[7,7]],
#                                            output=None, order=1, mode='constant',
#                                            cval=0.0, prefilter=True)
#print deproject1

xy_coords = numpy.swapaxes(retarray,0,1)
print(xy_coords)

deproject = scipy.ndimage.interpolation.map_coordinates(input=img, coordinates=xy_coords,
                                            output=None, order=1, mode='constant',
                                            cval=0.0, prefilter=True)

print(deproject.shape)

deproject_2d = numpy.reshape(deproject, (xd,yd))

pyfits.PrimaryHDU(data=img[:xd,:yd]).writeto("input.fits", overwrite=True)
primhdu = pyfits.PrimaryHDU(data=deproject_2d)
primhdu.header.update("CRPIX1", 1.0)
primhdu.header.update("CRPIX2", 1.0)
primhdu.header.update("CRVAL1", minRA)
primhdu.header.update("CRVAL2", minDec)
primhdu.header.update("CD1_1", pixelscale)
primhdu.header.update("CD2_2", pixelscale)
primhdu.header.update("CUNIT1", 'deg')
primhdu.header.update("CUNIT2", 'deg')
primhdu.header.update("CTYPE1", 'RA---TAN')
primhdu.header.update("CTYPE2", 'DEC--TAN')

primhdu.writeto("output.fits", overwrite=True)


#(©)Codexbotz

from pyrogram import __version__
from bot import Bot
from config import OWNER_ID
from pyrogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery

@Bot.on_callback_query()
async def cb_handler(client: Bot, query: CallbackQuery):
    data = query.data
    if data == "about":
        await query.message.edit_text(
            text = f"Привет! \nЯ могу сохранять файлы и выдавать их по определенной ссылке. Могу использоваться как в личных целях, так и для каналов. \n\nМеня создал @dA5niles с помощью готового кода, переведя на русский язык. За помощью и тестированием обращайтесь к нему. \n\nИсходный код - https://github.com/CodeXBotz/File-Sharing-Bot/ \nКод под русский язык - https://github.com/da5niles/FileBot      \n\nТех.информация:\n○ Creator : This Person\n○ Language : Python3\n○ Library : Pyrogram asyncio {__version__}\n○ Source Code : Click here\n○ Channel : @CodeXBotz\n○ Support Group : @CodeXBotzSupport",
            disable_web_page_preview = True,
            reply_markup = InlineKeyboardMarkup(
                [
                    [
                        InlineKeyboardButton("🔒 Close", callback_data = "close")
                    ]
                ]
            )
        )
    elif data == "close":
        await query.message.delete()
        try:
            await query.message.reply_to_message.delete()
        except:
            pass


import plotly.graph_objects as go
from plotly import subplots
import plotly.express as px
import dash
import dash_html_components as html
import dash_core_components as dcc
import dash_daq as daq

def impact_figure(impact):
  figure = go.Figure()

  figure.add_trace(
    go.Surface(
      x = impact.X,
      y = impact.Y,
      z = impact.Z
    )
  )

  figure.update_layout(
    scene = dict(
      xaxis_title = 'X (mm)',
      yaxis_title = 'Y (mm)',
      zaxis_title = 'Z (µm)',
    ),
    font_size = 10,
    height = 600,
    margin = dict(
      l = 20,
      r = 10,
      b = 50,
      t = 50
    )
  )

  return figure, [
    html.Div(
      id = 'impact-graph-header',
      className = 'impact-graph-header'
    ),
    dcc.Graph(
      id = 'impact-graph',
      figure = figure,
      config = {
        'displaylogo': False,
        'toImageButtonOptions': {
          'format': 'png',
          'height': None,
          'width': None,
          'scale': 1
        }
      }
    )
  ]

def update_impact(impact, figure, num_contours, colorscale, projection, view, x_range, y_range, z_scale):
  # contours
  if num_contours:
    contours = dict(
      z = dict(
        show = True,
        start = impact.zmin,
        end = impact.zmax,
        size = (impact.zmax - impact.zmin) / (num_contours)
      ),
    )
  else:
    contours = dict(
      z = dict(
        show = False
      )
    )
  figure.data[0]['contours'] = contours

  # colorscale
  figure.data[0]['colorscale'] = colorscale

  # projection
  figure.update_layout(
    scene_camera = dict(
      projection = dict(
        type = projection
      )
    )
  )

  # view
  if view == 'default':
    x_eye, y_eye, z_eye = 1.25, 1.25, 1.25
    x_up, y_up, z_up = 0, 0, 1
  elif view == 'top':
    x_eye, y_eye, z_eye = 0., 0., 2.5
    x_up, y_up, z_up = 0, 1, 0
  elif view == 'bottom':
    x_eye, y_eye, z_eye = 0., 0., -2.5
    x_up, y_up, z_up = 0, 1, 0
  elif view == 'front':
    x_eye, y_eye, z_eye = 0., 2.5, 0.
    x_up, y_up, z_up = 0, 0, 1
  elif view == 'back':
    x_eye, y_eye, z_eye = 0., -2.5, 0.
    x_up, y_up, z_up = 0, 0, 1
  elif view == 'right':
    x_eye, y_eye, z_eye = 2.5, 0, 0.
    x_up, y_up, z_up = 0, 0, 1
  elif view == 'left':
    x_eye, y_eye, z_eye = -2.5, 0, 0.
    x_up, y_up, z_up = 0, 0, 1
  figure.update_layout(
    scene_camera = dict(
      up = dict(
        x = x_up,
        y = y_up,
        z = z_up
      ),
      center = dict(
        x = 0,
        y = 0,
        z = 0
      ),
      eye = dict(
        x = x_eye,
        y = y_eye,
        z = z_eye
      )
    )
  )

  # x- and y-range
  figure.update_layout(
    scene = dict(
      xaxis = dict(
        range = (x_range[0], x_range[1])
      ),
      yaxis = dict(
        range = (y_range[0], y_range[1])
      )
    )
  )

  # z_scale
  figure.update_scenes(
    aspectmode = 'manual',
    aspectratio = dict (
      x = (x_range[1] - x_range[0]) / (y_range[1] - y_range[0]),
      y = 1,
      z = float(z_scale) if z_scale else 1
    )
  )

  return figure

def impact_toolbar(impact):
  return [
    html.H2('Impact Toolbar'),
    # contours
    html.Div(
      id = 'impact-contour-container',
      className = 'impact-toolbar-subcontainer',
      children = [
        html.H6('Number of Contours'),
        html.Div(
          id = 'contour-slider-container',
          className = 'contour-slider-container',
          children = [
            dcc.Slider(
              id = 'num-contours-slider',
              className = 'num-contours-slider',
              min = 0,
              max = 30,
              step = 1,
              value = 0
            ),
            html.Div(id = 'display-num-contours')
          ]
        )
      ]
    ),
    # colorscale
    html.Div(
      id = 'impact-colorscale-container',
      className = 'impact-contour-container',
      children = [
        html.H6('Colorscale'),
        dcc.Dropdown(
          id = 'colorscale-dropdown',
          className = 'colorscale-dropdown',
          options = [
            {
              'label': 'Jet',
              'value': 'Jet'
            },
            {
              'label': 'Viridis',
              'value': 'Viridis'
            },
            {
              'label': 'Red-Blue',
              'value': 'RdBu'
            }
          ],
          value = 'Jet'
        )
      ]
    ),
    # projection
    html.Div(
      id = 'impact-projection-container',
      className = 'impact-projection-container',
      children = [
        html.H6('Projection'),
        dcc.Dropdown(
          id = 'projection-dropdown',
          className = 'projection-dropdown',
          options = [
            {
              'label': 'Orthographic',
              'value': 'orthographic'
            },
            {
              'label': 'Perspective',
              'value': 'perspective'
            }
          ],
          value = 'orthographic'
        )
      ]
    ),
    # view
    html.Div(
      id = 'impact-view-container',
      className = 'impact-view-container',
      children = [
        html.H6('View'),
        dcc.Dropdown(
          id = 'view-dropdown',
          className = 'view-dropdown',
          options = [
            {
              'label': 'Default View',
              'value': 'default'
            },
            {
              'label': 'Top View (+XY)',
              'value': 'top'
            },
            {
              'label': 'Bottom View (-XY)',
              'value': 'bottom'
            },
            {
              'label': 'Front View (+XZ)',
              'value': 'front'
            },
            {
              'label': 'Back View (-XZ)',
              'value': 'back'
            },
            {
              'label': 'Right View (+YZ)',
              'value': 'right'
            },
            {
              'label': 'Left View (-YZ)',
              'value': 'left'
            }
          ],
          value = 'default'
        )
      ]
    ),
    # x-range
    html.Div(
      id = 'impact-xrange-container',
      className = 'impact-xrange-container',
      children = [
        html.H6('X-Axis Range'),
        html.Div(
          id = 'x-range-slider-container',
          className = 'x-range-slider-container',
          children = [
            html.Div(id = 'left-x-range-slider'),
            dcc.RangeSlider(
              id = 'x-range-slider',
              className = 'x-range-slider',
              min = 0,
              max = impact.xrange,
              step = impact.xrange / 25,
              value = [0, impact.xrange]
            ),
            html.Div(id = 'right-x-range-slider')
          ]
        )
      ]
    ),
    # y-range
    html.Div(
      id = 'impact-yrange-container',
      className = 'impact-yrange-container',
      children = [
        html.H6('Y-Axis Range'),
        html.Div(
          id = 'y-range-slider-container',
          className = 'y-range-slider-container',
          children = [
            html.Div(id = 'left-y-range-slider'),
            dcc.RangeSlider(
              id = 'y-range-slider',
              className = 'y-range-slider',
              min = 0,
              max = impact.yrange,
              step = impact.yrange / 25,
              value = [0, impact.yrange]
            ),
            html.Div(id = 'right-y-range-slider')
          ]
        )
      ]
    ),
    # z-scale
    html.Div(
      id = 'impact-zscale-container',
      className = 'impact-zscale-container',
      children = [
        html.H6('Z-Axis (Proportion to Default)'),
        html.Div(
          id = 'z-scale-slider-container',
          className = 'z-scale-slider-container',
          children = [
            dcc.Input(
              id = 'z-scale-input',
              className = 'z-scale-input',
              type = 'number',
              min = 0.1,
              max = 100,
              step = 0.1,
              placeholder = 1,
              value = 1
            )
          ]
        )
      ]
    )
  ]

def scanline_toolbar(impact):
  scanline_info = []
  for i, scanline in enumerate(impact.scanlines):
    scanline_info.append(
      html.Div(
        id = f'scanline-toolbar-info-{i}',
        children = [
          html.Button(
            children = f'View Scanline {i + 1}: {scanline.ypos:.5f}mm',
            className = 'scanline-view-button',
            id = dict(
              type = 'scanline-view-button',
              index = i
            )
          ),
          html.Div(
            className = 'scanline-regression-info',
            id = dict(
              type = 'scanline-regression-info',
              index = i
            ),
            children = [
              html.Div(
                id = 'scanline-regression-slope-container',
                className = 'scanline-regression-slope-container',
                children = [
                  html.P('Slope: '),
                  dcc.Input(
                    id = dict(
                      type = 'scanline-regression-slope',
                      index = i
                    ),
                    className = 'scanline-regression-slope',
                    type = 'number',
                    step = 0.01,
                    value = round(scanline.slope, 2),
                    placeholder = round(scanline.slope, 2)
                  ),
                ]
              ),
              html.Div(
                id = 'scanline-regression-intercept-container',
                className = 'scanline-regression-intercept-container',
                children = [
                  html.P('Intercept: '),
                  dcc.Input(
                    id = dict(
                      type = 'scanline-regression-intercept',
                      index = i
                    ),
                    className = 'scanline-regression-intercept',
                    type = 'number',
                    step = 0.01,
                    value = round(scanline.intercept, 2),
                    placeholder = round(scanline.intercept, 2)
                  )
                ]
              )
            ]
          ),
          html.Div(
            id = dict(
              type = 'scanline-local-extrema',
              index = i
            ),
            className = 'scanline-local-extrema',
            children = [
              # local minima
              html.H6('Local Minima'),
              html.Div(
                id = dict(
                  type = 'scanline-local-minima',
                  index = i
                ),
                className = 'scanline-local-minima',
                children = [
                  html.P(f'({minima[0]:.5f}, {minima[1]:.5f})') for minima in scanline.minima[0]
                ]
              ),
              # local maxima
              html.H6('Local Maxima'),
              html.Div(
                id = dict(
                  type = 'scanline-local-maxima',
                  index = i
                ),
                className = 'scanline-local-maxima',
                children = [
                  html.P(f'({maxima[0]:.5f}, {maxima[1]:.5f})') for maxima in scanline.maxima[0]
                ]
              )
            ]
          )
        ]
      )
    )

  return [
    html.H2('Scanline Toolbar'),
    html.Div(
      id = 'scanline-toolbar-view-all',
      className = 'scanline-toolbar-view-all',
      children = [
        html.H6('All Scanlines'),
        dcc.RadioItems(
          id = 'scanline-view-all-button',
          className = 'scanline-view-all-button',
          options = [
            {
              'label': 'Display All Scans',
              'value': 'show'
            },
            {
              'label': 'Hide All Scans',
              'value': 'hide'
            }
          ],
          value = 'show'
        )
      ]
    ),
    html.Div(
      id = 'scanline-toolbar-scanlines',
      className = 'scanline-toolbar-scanlines',
      children = [
        html.H6('Individual Scanlines'),
        *[scanline for scanline in scanline_info]
      ]
    )
  ]

def all_scanline_figure(impact, visible = None):
  figure = go.Figure()

  figure.add_traces(
    [
      go.Scatter(
        x = scanline.data_corrected_smooth[:, 0],
        y = scanline.data_corrected_smooth[:, 1],
        name = f'Scanline {i + 1}',
        visible = visible
      )
      for i, scanline in enumerate(impact.scanlines)
    ]
  )

  figure.update_layout(
    height = 500,
    title_text = 'Superimposed Scanlines',
    xaxis_title = 'X (mm)',
    yaxis_title = 'Z (µm)'
  )

  return [
    html.Div(
      id = 'scanline-graphs-header',
      className = 'scanline-graphs-header'
    ),
    dcc.Graph(
      id = 'scanline-graph-all',
      figure = figure
    )
  ]

def scanline_figure(impact, index):
  scanline = impact.scanlines[index]

  figure = subplots.make_subplots(
    rows = 3,
    subplot_titles = (
      'Raw Data',
      'Slope-Corrected Data',
      'Smoothened Slope-Corrected Data'
    )
  )

  figure.add_traces(
    [
      go.Scatter(
        x = scanline.data[:, 0],
        y = scanline.data[:, 1]
      ),
      go.Scatter(
        x = scanline.data_corrected[:, 0],
        y = scanline.data_corrected[:, 1],
      ),
      go.Scatter(
        x = scanline.data_corrected_smooth[:, 0],
        y = scanline.data_corrected_smooth[:, 1],
      )
    ],
    rows = [1, 2, 3],
    cols = [1, 1, 1]
  )

  figure.update_xaxes(title_text = 'X (mm)')
  figure.update_yaxes(title_text = 'Y (µm)')

  figure.update_layout(
    height = 800,
    title_text = f'Scanline {index + 1}: {scanline.ypos:.5f}mm',
    showlegend = False
  )

  return [
    html.Div(
      id = 'scanline-graphs-header',
      className = 'scanline-graphs-header'
    ),
    dcc.Graph(
      id = dict(
        type = 'scanline-graph',
        index = index
      ),
      figure = figure
    )
  ]


import json
import csv
import urllib.parse
import boto3
import requests

s3 = boto3.client('s3')

def handler(event, context):
  bucket = event['Records'][0]['s3']['bucket']['name']
  key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
  api_data = []

  try:
    response = s3.get_object(Bucket=bucket, Key=key)
    csv_data = response['Body'].read()
    reader = csv.reader(csv_data.decode().splitlines())

    first_row = next(reader)
    n = len(first_row)

    # Iterate through the rows and get the data in a list
    for rw in reader:
        tmp = {}
        for i in range(n):
            tmp[first_row[i]] = rw[i]
        api_data.append(tmp)
    print("api_data", api_data)

    def divide_chunks(l, n):
      for i in range(0, len(l), n):
        yield l[i:i+n]

    chunks = list(divide_chunks(api_data, 100))
    print("chunks", chunks)

    for chunk in chunks:
      response = requests.post('http://techwondoebackend.ananddhakane.tech/register', json=chunk)
      if response.status_code == 200:
        data = response.json()
        print("Data inserted Successfully!!!", data)
      else:
        print('Error: ', response.status_code, response)

  except Exception as e:
    print(e)
    print("Error getting object!")


from math import cos, degrees, floor, log10, sin, radians, tan
from random import randint
from time import sleep
from threading import Thread

from pygame import Vector2
from pygame.surface import Surface
from engine.assetsManager import AssetsManager
from engine.objects import Object, Components
from engine import Window
from engine.sceneManager import Scene
from engine.colliders import Collider, CircleCollider
from engine.util import get_lerp, lerp

class HealthBar:
	def __init__(self, max_health:int, location:Vector2, init_health=None):
		if init_health == None: init_health = max_health
		self.health = min(max_health, init_health)
		self.max_health = max_health
		self.bar_length = 200
		self.ratio = self.bar_length / self.max_health # pixels per unit health
		self.location = location
		self.height = 25

		self.visual_health = init_health
		self.health_change_speed = 0.5
	def set_health(self, value:int):
		self.health = max(0,min(self.max_health, value))
	def get_health(self) -> int:
		return self.health
	def render(self, screen, pygame):
		#self.visual_health
		#if self.health: pygame.draw.rect(screen, (255,0,0), (self.location.x, self.location.y, self.health*self.ratio, self.height))
		#pygame.draw.rect(screen, (255,255,255), (self.location.x, self.location.y, self.bar_length, self.height), 4)
		# ! this is meant to look good but it doesn't really work
		# TODO
		transition_width = 0
		transition_color = (255,0,0)

		if self.visual_health < self.health:
			self.visual_health += self.health_change_speed
			transition_width = (self.health - self.visual_health)/self.ratio
			transition_color = (0,255,0)
		elif self.visual_health > self.health:
			self.visual_health -= self.health_change_speed
			transition_width = (self.health - self.visual_health)/self.ratio
			transition_color = (255,255,0)

		if self.health: pygame.draw.rect(screen, (255,0,0), (self.location.x+(self.visual_health*self.ratio), self.location.y, (self.health-self.visual_health)*self.ratio, self.height))
		if self.health: pygame.draw.rect(screen, (255,0,0), (self.location.x, self.location.y, self.health*self.ratio, self.height))
		pygame.draw.rect(screen, (255,255,255), (self.location.x, self.location.y, self.bar_length, self.height), 4)

	def __iadd__(self, other:int):
		self.health += other
		return self
	def __isub__(self, other:int):
		self.health -= other
		return self

class Planet:
	def __init__(self, name:str, planetData:dict) -> None:
		self.name:str = name
		self.order:int = planetData["order"]
		self.distance:int = planetData["distance"]
		self.mass:int = planetData["mass"]

		self.position = None
		self.diameter = None
	def bind_image(self, image_asset_id: int):
		self.image_asset_id:int = image_asset_id

	def calculate_position(self, screensize: tuple[int,int], orbitno:int) -> int:
		if self.position == None:
			centre = Vector2(screensize[0]/2,screensize[1]/2)
			if self.distance == 0: self.position = centre - self.size/2
			else:
				MAXDISTANCE = 270000000
				OFFSET = 150
				PLANET_COUNT = 5-1
				theta = 360/PLANET_COUNT * orbitno
				rand_angle = randint(floor(-360/PLANET_COUNT/3),floor(360/PLANET_COUNT/3))
				distance = OFFSET + floor(self.distance/MAXDISTANCE*((min(screensize)-OFFSET)/2-100))
				self.position = centre + Vector2(cos(radians(theta+rand_angle)),sin(radians(theta+rand_angle)))*distance
		self.position -= self.size/2
		return self.position
	def calculate_diameter(self):
		if self.name == "sun":
			self.diameter = 75
		else:
			MAXMASS = (6.2E24)
			MAXDIAMETER = 25
			DIAMETEROFFSET = 20
			self.diameter = DIAMETEROFFSET + floor((self.mass)/MAXMASS*MAXDIAMETER)
		self.size = Vector2(self.diameter,self.diameter)
		return self.diameter
	def createGameObject(self, window_dimensions: tuple, assetsManager:AssetsManager, orbitno:int) -> Object:
		self.calculate_diameter()
		self.calculate_position(window_dimensions, orbitno)
		self.obj = Object(self.name,self.position, size=self.size, tags=["planet"])
		self.obj.addComponent(Components.Image(self.image_asset_id), assetsManager)
		self.obj.collider = CircleCollider()
		return self.obj

class Player:
	def __init__(self, image_asset_id:int, player_id=0):
		self.position:Vector2 = Vector2(100,100)
		self.image_asset_id:int = image_asset_id

		self.ROTATION_SPEED = 60
		self.ACCEL_SPEED = 0.7
		self.GRAVITY_SCALE = 5e-25
		self.MAX_VELOCITY = 100

		self.cooldown = 0

		self.player_id = player_id
		self.id_str = ('' if player_id == 0 else str(player_id))
		self.objectname = "player" + (str(player_id) if player_id else "")
		self.scene = ("default" if not player_id else "1v1Scene")
		# ! this will probably cause errors
		# TODO
		self.obj_name = "player"+self.id_str
		print(self.scene,'/',self.obj_name)

		self.keybinds = (
			{'forwards':'w','left':'a','right':'d','shoot':'s'}
			if player_id <= 1 else
			{'forwards':'UP','left':'LEFT','right':'RIGHT','shoot':'DOWN'}
			)
	def createGameObject(self, assetsManager:AssetsManager) -> Object:
		self.obj = Object(self.obj_name,self.position,size=Vector2(50,50), tags=["player"])
		self.obj.addComponent(Components.Image(self.image_asset_id), assetsManager)
		self.obj.collider = CircleCollider()
		return self.obj

	def update(self, planets:list[Planet], window:Window, dt:float):
		screen_dimensions = window.dimensions
		self.controls(window, planets, dt)
		self.check_edges(window, screen_dimensions)

	def controls(self, window:Window, planets:list[Planet], dt:float):
		a_pressed = window.input_manager.get_key(self.keybinds['left'])
		d_pressed = window.input_manager.get_key(self.keybinds['right'])
		if a_pressed and (not d_pressed):
			window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.rotation += self.ROTATION_SPEED*dt
		elif (not a_pressed) and d_pressed:
			window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.rotation -= self.ROTATION_SPEED*dt

		w_pressed = window.input_manager.get_key(self.keybinds['forwards'])
		if w_pressed:
			accel_force = Vector2(0,0)
			accel_force.from_polar(
				(self.ACCEL_SPEED, 270-window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.rotation)
			)
			window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.velocity += accel_force
			if randint(1,2):
				for _ in range(5):
					vel, engine_offset = Vector2(0,0), Vector2(0,0)
					engine_offset.from_polar((-25,window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.rotation-90+randint(-10,10)))
					engine_offset.x = -engine_offset.x
					vel.from_polar((0.2,window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.rotation-90+randint(-75,75)))
					window.sceneManager.scenes[self.scene].particle_emitters["engine"+self.id_str].emit(
						list(window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.position + \
							window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.size/2 + engine_offset),
						list(vel)
					)

		s_pressed = window.input_manager.get_key(self.keybinds['shoot'])
		self.cooldown = max(0, self.cooldown-dt)
		RELOAD_TIME = 0.5
		if s_pressed:
			# Fire
			try:
				if self.cooldown <= 0:
					self.cooldown += RELOAD_TIME
					vel, turret_offset = Vector2(0,0), Vector2(0,0)
					turret_offset.from_polar((-25,window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.rotation+90))
					turret_offset.x = -turret_offset.x
					VEL_MAG_DELTA = 75
					vel.from_polar((abs(window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.velocity.magnitude())+VEL_MAG_DELTA,
						(-window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.rotation-90+randint(-3,3))))
					window.sceneManager.scenes[self.scene].particle_emitters["turret"+self.id_str].emit(
						list(window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.position + \
							window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.size/2 + turret_offset),
						list(vel),
						(15,18)
					)
			except:
				pass # Scene not created turret yet

		if window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.velocity.magnitude_squared() >= self.MAX_VELOCITY*self.MAX_VELOCITY:
			window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.velocity = \
				window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.velocity.normalize()*self.MAX_VELOCITY

		window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.force = self.calcualte_resultant_gravity(planets, window)

	def check_edges(self, window:Window, screen_dimensions:tuple):
		player_position = window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.position + \
			window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.size/2
		centre_offset = window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.size/2
		if not 0 <= player_position.x <= screen_dimensions[0]:
			window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.position.x = \
				(screen_dimensions[0] if player_position.x-centre_offset.x<=0 else 0)-centre_offset.x
		elif not 0 <= player_position.y <= screen_dimensions[1]:
			window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.position.y = \
				(screen_dimensions[1] if player_position.y-centre_offset.y<=0 else 0)-centre_offset.y

	def calcualte_resultant_gravity(self, planets:list[Planet], window:Window):
		gravity = Vector2(0,0)
		for planet in planets:
			delta = (
				(window.sceneManager.scenes[self.scene].objects[planet.name].transform.position + \
					(window.sceneManager.scenes[self.scene].objects[planet.name].transform.size/2)) - \
					(window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.position + \
						(window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.size/2)))

			try:
				magnitude = delta.magnitude()
				delta = Vector2(planet.mass*delta.x/magnitude,planet.mass*delta.y/magnitude)*self.GRAVITY_SCALE
			except:
				delta = Vector2(0,0)
			window.draw_line(
				(window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.position + \
					(window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.size/2)),
				(window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.position + \
					(window.sceneManager.scenes[self.scene].objects[self.obj_name].transform.size/2))+delta*10
			)
			gravity += delta
		return gravity

	def link_health_bar(self, hb:HealthBar):
		self.set_health = hb.set_health
		self.get_health = hb.get_health

class PathPrediction:
	def __init__(self, iterations:int, scene:str, object_name):
		self.MAX_ITERATIONS = iterations
		self.GRAVITY_SCALE = 5e-25
		self.scene = scene
		self.object_name = object_name
	def update(self, planets:list[Planet], window:Window):
		dt=0.25
		last_point:Vector2 = self.get_player_pos(window)
		velocity:Vector2 = window.sceneManager.scenes[self.scene].objects[self.object_name].transform.velocity.copy()
		for i in range(self.MAX_ITERATIONS):
			force = self.calcualte_resultant_gravity(planets, window, last_point)
			velocity += force*dt
			new_point = last_point + velocity*dt
			if not (0 < new_point.x < window.dimensions[0] and 0 < new_point.y < window.dimensions[1]):
				break
			window.draw_line(last_point, new_point)
			last_point = new_point

	def get_player_pos(self, window:Window) -> Vector2:
		return (window.sceneManager.scenes[self.scene].objects[self.object_name].transform.position + \
			   (window.sceneManager.scenes[self.scene].objects[self.object_name].transform.size/2)).copy()

	def calcualte_resultant_gravity(self, planets:list[Planet], window:Window, position:Vector2):
		gravity = Vector2(0,0)
		for planet in planets:
			delta = (
				(window.sceneManager.scenes[self.scene].objects[planet.name].transform.position + \
					(window.sceneManager.scenes[self.scene].objects[planet.name].transform.size/2)) - \
					position)
			try:
				magnitude = delta.magnitude()
				delta = Vector2(planet.mass*delta.x/magnitude,planet.mass*delta.y/magnitude)*self.GRAVITY_SCALE
			except:
				delta = Vector2(0,0)
			gravity += delta
		return gravity

def menuScene_on_update(scene:Scene, dt:float, window:Window):
	# Sets the position of the shuttle when the menu screen is open
	if scene.is_transfer:
		scene.transfer_value += dt / scene.transfer_time
		# TODO Calculate position
		scene.objects["shuttle"].transform.position = Vector2(0,0)
	else:
		scene.orbit_angle += scene.angular_velocity * dt
		# TODO Calculate position
		pos = scene.planet_pos + Vector2(cos(radians(scene.orbit_angle)), sin(radians(scene.orbit_angle)))*scene.orbit_radius
		scene.objects["shuttle"].transform.position = pos
		scene.objects["shuttle"].transform.rotation = 180 - scene.orbit_angle

	pos = window.input_manager.get_mouse_pos()
	# ! This does not work at all (kinda) and looks really janky
	# TODO
	# if scene.storage["waiting"]:
	# 	ang = Vector2(1,0).angle_to(scene.objects["shuttle"].transform.position-scene.planet_pos)
	# 	if ang > scene.storage["wanted_angle"] and scene.storage["angle_reset"]:
	# 		scene.storage["waiting"] = False
	# 	elif ang < scene.storage["wanted_angle"] and scene.storage["angle_reset"]:
	# 		scene.storage["angle_reset"] = True

	if scene.storage["in_transfer"]: #and (not scene.storage["waiting"]):
		scene.storage["transfer_time"] += dt
		scene.objects["shuttle"].transform.position = scene.storage["orbit_transfer"].__call__(scene.storage["transfer_time"]) - (scene.objects["shuttle"].transform.size/2)
		if scene.storage["transfer_time"] > 1:
			scene.storage["in_transfer"] = False
			scene.planet_pos = scene.objects[scene.storage['planet_orbit']].transform.position
			scene.orbit_angle = Vector2(1,0).angle_to(scene.objects["shuttle"].transform.position-scene.planet_pos)
		return # dont check the mouse position again
	# get the planet the mouse is currently over and calculate a orbital path
	for obj in scene.objects.values():
		if "planet" in obj.tags:
			col:bool = obj.collider.test(pos)
			if col:
				if scene.storage["planet_orbit"] != obj.name:
					scene.storage["in_transfer"] = True
					scene.storage["waiting"] = True
					scene.storage["transfer_time"] = 0
					scene.storage["orbit_transfer"], scene.storage["wanted_angle"] = get_transfer(
						scene.objects[obj.name].transform.position + (scene.objects[obj.name].transform.size/2),
						scene.objects[obj.name].transform.size.x/2+scene.orbit_radius,
						scene.objects[scene.storage["planet_orbit"]].transform.position + (scene.objects[scene.storage["planet_orbit"]].transform.size/2),
						scene.objects[scene.storage["planet_orbit"]].transform.size.x/2+scene.orbit_radius,
					)
					scene.storage["angle_reset"] = (Vector2(1,0).angle_to(scene.objects["shuttle"].transform.position-scene.planet_pos) < scene.storage["wanted_angle"])
				scene.storage['planet_orbit'] = obj.name

def get_transfer(c1:Vector2,r1:float,c2:Vector2,r2:float, theta=10) -> tuple[callable, float]:
	# Generate a funciton that returns the position of the shuttle during transfers and angle needed to start one
	P1 = c1 + (c2-c1).normalize().rotate(-90+theta)*r1
	P3 = c2 + (c2-c1).normalize().rotate(-90-theta)*r2
	a = -1/(tan(-90+theta+(c2-c1).as_polar()[1]))
	b = 1/(tan(-90+theta+(c2-c1).as_polar()[1]))*P1.x+P1.y
	c = -1/(tan(-90-theta+(c2-c1).as_polar()[1]))
	d = 1/(tan(-90-theta+(c2-c1).as_polar()[1]))*P3.x+P3.y
	P2 = Vector2(
		(d-b)/(a-c),
		a*(d-b)/(a-c)+b
	)
	def foo(t:float):
		return lerp(t,
			lerp(t,P1,P2),
			lerp(t,P2,P3)
		)
	angle = Vector2(1,0).angle_to(P1-c1)
	return foo, angle

def on_render_1v1Scene(self:Scene, pygame, screen:Surface, dt:float):
	self.storage['player1hb'].render(screen, pygame)
	self.storage['player2hb'].render(screen, pygame)

def bullet_collision_callback(window:Window, name:str, other_name:str, life:float):
	def check_if_kill():
		if window.sceneManager.current_scene.storage["player1hb"].get_health() == 0:
			on_end_game(window, 1)
		elif window.sceneManager.current_scene.storage["player2hb"].get_health() == 0:
			on_end_game(window, 2)
	if window.sceneManager.current_scene_name == "1v1Scene":
		if other_name == "player1" and (not name == "turret1"):
			window.sceneManager.current_scene.storage["player1hb"] -= 1
			check_if_kill()
			return True
		elif other_name == "player2" and (not name == "turret2"):
			window.sceneManager.current_scene.storage["player2hb"] -= 1
			check_if_kill()
			return True
		elif other_name in ['player1', 'player2']:
			return False
		else:
			return True
	return False

def on_object_collision(window:Window, objA:Object, objB:Object):
	if ("player" in objA.tags) and ("planet" in objB.tags):
		#window.sceneManager.current_scene.objects[objA.name]
		window.sceneManager.current_scene.storage[objA.name.lower()+"hb"].set_health(0)
		t1 = Thread(target=on_end_game, args=(window, (1 if objA.name == "player1" else 2)), daemon=True)
		t1.start()

def explosion(window:Window, player_id:int):
	for i in range(300):
		pe = window.sceneManager.current_scene.particle_emitters["exp"+str(player_id)]
		vel = Vector2(0,0)
		vel.from_polar((randint(10,50),randint(0,360)))
		pe.emit(
			window.sceneManager.current_scene.objects["player"+str(player_id)].transform.position + (window.sceneManager.current_scene.objects["player"+str(player_id)].transform.size/2),
			vel, (20,30)
		)
		window.sceneManager.current_scene.objects["player"+str(player_id)].image.should_render = False

def on_end_game(window:Window, player_id:int):
	if not window.sceneManager.current_scene.storage['reset_timer']:
		explosion(window, player_id)
		window.sceneManager.current_scene.objects["endMessage"].text.text = f"Player {('2' if player_id == 1 else '1')} Wins!"
		window.sceneManager.current_scene.objects["endMessage"].text.should_render = True
		window.sceneManager.current_scene.objects["msgBox"].primitive.should_render = True
		window.sceneManager.current_scene.storage['reset_timer'] = float(5)
	return

def on_1v1Scene_update(scene:Scene, dt:float, window:Window):
	if type(scene.storage['reset_timer']) == float:
		if scene.storage['reset_timer'] < 0:
			window.sceneManager.reset_scene("MenuScene")
			window.sceneManager.loadScene("MenuScene")
			scene.storage['reset_timer'] = None
		else:
			scene.storage['reset_timer'] -= dt


import imp
from importlib.abc import ExecutionLoader
from pyexpat import model
from tkinter import Widget
from django import forms
from .models import Reception,Rating,Ingredient

class ingredientform(forms.ModelForm):
   class Meta:
      model = Ingredient
      exclude = ("recipe","ingredient",)

ingredientformset = forms.inlineformset_factory(Reception,Ingredient,form=ingredientform)

class receptionform(forms.ModelForm):
   class Meta:
      model = Reception
      fields= ('title','author','describe',)
      widgets = {
         'title' : forms.TextInput(attrs={'class':'form-control'}),
         'author' : forms.TextInput(attrs={'class':'form-control','value':'','id':'user','type':'hidden'}),
         'describe' : forms.Textarea(attrs={'class':'form-control'}),

      }

class Ratingf(forms.ModelForm):
   class Meta:
      model = Rating
      fields = '__all__'


#!/usr/bin/env python

import adventofcode

def parse_input_line(line):
    """
    >>> parse_input_line("set p 316")
    ['set', 'p', '316']
    """
    return line.split()

def run_program(instructions):
    reg = {}
    ip = 0
    while ip >= 0 and ip < len(instructions):
        inst = instructions[ip]
        if len(inst) > 2:
            val = reg.get(inst[2], 0) if inst[2].isalpha() else int(inst[2])
        else:
            val = 0
        if inst[0] == "set":
            reg[inst[1]] = val
        elif inst[0] == "add":
            reg[inst[1]] = reg.get(inst[1], 0) + val
        elif inst[0] == "mul":
            reg[inst[1]] = reg.get(inst[1], 0) * val
        elif inst[0] == "mod":
            reg[inst[1]] = reg.get(inst[1], 0) % val
        elif inst[0] == "snd":
            reg["snd"] = reg.get(inst[1], 0)
        elif inst[0] == "rcv":
            if reg.get(inst[1], 0) != 0:
                reg[inst[1]] = reg.get("snd", 0)
                return reg[inst[1]]
        elif inst[0] == "jgz":
            if reg.get(inst[1], 0) > 0:
                ip += val - 1
        ip += 1
    return "done"

def part1(instructions):
    return run_program(instructions)

def test1(lines):
    """
    >>> test1(["set a 1","add a 2","mul a a","mod a 5","snd a","set a 0","rcv a","jgz a -1","set a 1","jgz a -2"])
    4
    """
    instructions = [parse_input_line(line) for line in lines]
    return part1(instructions)

class Program(object):
    def __init__(self, id, inqueue, outqueue, instructions):
        self.id = id
        self.inq = inqueue
        self.outq = outqueue
        self.instructions = instructions
        self.reg = {'p': id}
        self.ip = 0
        self.sendcount = 0

    def argval(self, arg):
        return self.reg.get(arg, 0) if arg.isalpha() else int(arg)

    def run(self):
        if self.ip >= 0 and self.ip < len(self.instructions):
            inst = self.instructions[self.ip]
            val = self.argval(inst[2]) if len(inst) > 2 else 0
            if inst[0] == "set":
                self.reg[inst[1]] = val
            elif inst[0] == "add":
                self.reg[inst[1]] = self.reg.get(inst[1], 0) + val
            elif inst[0] == "mul":
                self.reg[inst[1]] = self.reg.get(inst[1], 0) * val
            elif inst[0] == "mod":
                self.reg[inst[1]] = self.reg.get(inst[1], 0) % val
            elif inst[0] == "snd":
                self.outq.insert(0, self.argval(inst[1]))
                self.sendcount += 1
            elif inst[0] == "rcv":
                if len(self.inq) > 0:
                    self.reg[inst[1]] = self.inq.pop()
                else:
                    return "wait"
            elif inst[0] == "jgz":
                if self.argval(inst[1]) > 0:
                    self.ip += val - 1
            self.ip += 1
            return "run"
        return "done"

def part2(instructions):
    queues = [[], []]
    programs = [Program(0, queues[0], queues[1], instructions), Program(1, queues[1], queues[0], instructions)]
    status = ["run", "run"]
    while status.count("run") > 0:
        last = status[:]
        status[0] = programs[0].run()
        status[1] = programs[1].run()
    return programs[1].sendcount

def test2(lines):
    """
    >>> test2(["snd 1","snd 2","snd p","rcv a","rcv b","rcv c","rcv d"])
    3
    """
    instructions = [parse_input_line(line) for line in lines]
    return part2(instructions)

def main():
    puzzle_input = adventofcode.read_input(18)
    instructions = [parse_input_line(x) for x in puzzle_input]
    adventofcode.answer(1, 2951, part1(instructions))
    adventofcode.answer(2, 7366, part2(instructions))

if __name__ == '__main__':
    import doctest
    doctest.testmod()
    main()


import json

def op_interpreter(area_iso: str, target: str, tags: list) -> str:
    """
    High-level interpreter for Overpass API query language.

    Args:
        area_iso (str): ISO code of the area to query.
        target (str): OSM target to query (e.g. "power", "waterway").
        tags (list): List of OSM tags to query.

    Returns:
        str: Overpass API query string.
    """
    try:
        with open(f'assets/osm/{target}-structure.json', 'r') as f:
            STRUCTURE = json.load(f)
    except FileNotFoundError:
        raise FileNotFoundError(f"{target} target not found.")

    mapped_tags = {}
    for tag in tags:
        for item in STRUCTURE:
            if tag == item['tag']:
                mapped_tags[tag] = item['type'][0]

    if not mapped_tags:
        raise ValueError(f"No tags found for {target} with {tags}")

    query = f"[out:json];\narea['ISO3166-1'~'{area_iso}']->.a;\n"

    query += "(\n"
    for tag, type_ in mapped_tags.items():
        query += f"  {type_}['{target}'='{tag}'](area.a);\n"
    query += ");\n"

    query += "out body;\n>;"
    return query


from pathlib import Path
from typing import Any, Dict, List, Literal, Optional, Sequence, Tuple, Union

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from astropy.visualization import LogStretch
from astropy.visualization.mpl_normalize import ImageNormalize
from matplotlib.offsetbox import AnchoredText
from scipy import interpolate

from . import utils

def plot_ramachandran(
    data: pd.DataFrame,
    x: str = "phi",
    y: str = "psi",
    col: Optional[str] = None,
    col_order: Optional[List[str]] = None,
    row: Optional[str] = None,
    row_order: Optional[List[str]] = None,
    height: int = 4,
    plot_type: Literal["density_scatter", "hexbin", "sns.scatterplot"] = "density_scatter",
    remove_axis_text: bool = False,
    path: Optional[Union[str, Path]] = None,
    **kwargs,
) -> sns.FacetGrid:
    g = sns.FacetGrid(
        data,
        col=col,
        col_order=col_order,
        row=row,
        row_order=row_order,
        sharex=True,
        sharey=True,
        height=height,
        aspect=1,
        despine=False,
        margin_titles=row is not None,
        gridspec_kws=dict(wspace=0.05, hspace=0.05),
    )
    name, *attrs = plot_type.split(".")
    plot_func = globals()[name]
    for attr in attrs:
        plot_func = getattr(plot_func, attr)
    g.map(plot_func, x, y, **kwargs)
    format_facet_grid_dihedral_axis(g, which="x")
    format_facet_grid_dihedral_axis(g, which="y")
    g.set_xlabels(r"$\phi$")
    g.set_ylabels(r"$\psi$")
    g.tick_params(axis="both", labelsize=8)
    if row is None:
        g.set_titles(template="{col_name}")
    else:
        g.set_titles(col_template="{col_name}", row_template="{row_name}")
    for ax in g.axes.flat:
        ax.set_aspect("equal")
        if remove_axis_text:
            ax.axes.get_xaxis().set_visible(False)
            ax.axes.get_yaxis().set_visible(False)
    if path is not None:
        g.figure.savefig(path, dpi=300, bbox_inches="tight", pad_inches=0.01)
    return g

def plot_distributions(
    data: pd.DataFrame,
    x: str,
    col: Optional[str] = None,
    row: Optional[str] = None,
    hue: Optional[str] = None,
    binwidth: float = 2 * np.pi / 100,
    sharex: bool = True,
    sharey: bool = False,
    height: int = 3,
    format_as_dihedral_axis: bool = True,
    xlabel: Optional[str] = None,
    path: Optional[Union[str, Path]] = None,
    add_kl_div: bool = True,
    **kwargs,
) -> sns.FacetGrid:
    g = sns.FacetGrid(
        data,
        hue=hue,
        col=col,
        row=row,
        sharex=sharex,
        sharey=sharey,
        height=height,
        margin_titles=row is not None,
        **kwargs,
    )
    g.map(sns.histplot, x, stat="density", binwidth=binwidth, linewidth=0.2)
    if row is None:
        g.set_titles("")
    else:
        g.set_titles(col_template="", row_template="{row_name}")
    if format_as_dihedral_axis:
        format_facet_grid_dihedral_axis(g)
    if xlabel is None:
        for label, ax in g.axes_dict.items():
            if row is None:
                ax.set_xlabel(rf"$\{label}$")  # LaTeX
            else:
                ax.set_xlabel(rf"$\{label[1]}$")
    else:
        g.set_xlabels(label=xlabel)
    g.set_ylabels(label="Density")
    g.tick_params(axis="y", labelsize=8)
    g.add_legend(title="", loc="upper left")
    if add_kl_div:

        def add_kldiv_to_plot(ax, kl_div):
            at = AnchoredText(
                f"KL = {kl_div:.4f}", prop=dict(size=10), frameon=True, loc="upper right"
            )
            at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2")
            at.patch.set(alpha=0.8, edgecolor=(0.8, 0.8, 0.8, 0.8))
            ax.add_artist(at)

        if col is None and row is None:
            kl_div = utils.compute_kl_divergence_from_dataframe(data, x)
            add_kldiv_to_plot(g.ax, kl_div[x])
        else:
            by = list(filter(None, [row, col]))
            kl_divs = data.groupby(by).apply(
                lambda d: utils.compute_kl_divergence_from_dataframe(d, x)
            )
            for label, ax in g.axes_dict.items():
                if kl_divs is not None:
                    kl_div = kl_divs.loc[label, x]
                    add_kldiv_to_plot(ax, kl_div)
    g.figure.tight_layout(pad=0.01, h_pad=0.1, w_pad=0.1)
    if path is not None:
        g.figure.savefig(path, dpi=600, bbox_inches="tight", pad_inches=0.01)
    return g

def plot_coverage(
    data: pd.DataFrame,
    x: str = "threshold",
    y: str = "cov",
    hue: str = "cov-type",
    col: str = "src",
    col_order: Sequence[str] = ("RMSD", "TFD"),
    path: Optional[Union[str, Path]] = None,
    **kwargs,
) -> sns.FacetGrid:
    g = sns.FacetGrid(
        data,
        hue=hue,
        col=col,
        col_order=col_order,
        sharex=False,
        height=4,
        despine=False,
        xlim=(0, data[x].max()),
        ylim=(0, 100),
        legend_out=False,
        **kwargs,
    )
    g.map(sns.lineplot, x, y)
    xlabels = {"RMSD": "Threshold (Å)", "TFD": "Threshold"}
    for label, ax in g.axes_dict.items():
        ax.set_xlabel(xlabels[label])
        if label == "TFD":
            ax.set_xlim(0, 1)
    g.set_ylabels("Coverage (%)")
    g.set_titles(template="{col_name}")
    g.add_legend(title="")
    if path is not None:
        g.figure.savefig(path, dpi=600, bbox_inches="tight", pad_inches=0.01)
    return g

def plot_ramachandran_plots(
    phi_psi_data: pd.DataFrame,
    plot_dir: Optional[Union[str, Path]] = None,
    name: str = "ramachandran",
    ext: str = ".png",
    col_order: Sequence[str] = ("Test", "Sampled"),
    as_rows: bool = False,
    residues: bool = False,
) -> None:
    if plot_dir is not None:
        plot_dir = Path(plot_dir)
        fname = f"{name}_residues{ext}" if residues else f"{name}{ext}"
        ramachandran_path = plot_dir / fname
    else:
        ramachandran_path = None

    col = "src"
    col_order = list(col_order)
    row = "num_residues" if residues else None
    row_order = ["4 residues", "5 residues", "6 residues"] if residues else None
    if as_rows:
        row, col = col, row
        row_order, col_order = col_order, row_order

    plot_ramachandran(
        phi_psi_data,
        col=col,
        col_order=col_order,
        row=row,
        row_order=row_order,
        height=3,
        s=1,
        edgecolors="none",
        cmap="magma",
        path=ramachandran_path,
    )

def plot_angle_and_dihedral_distributions(
    data: pd.DataFrame,
    plot_dir: Optional[Union[str, Path]] = None,
    ext: str = ".png",
    residues: bool = False,
) -> None:
    def get_path(name: str) -> Optional[Path]:
        if plot_dir is None:
            return None
        if residues:
            name += "_residues"
        fname = f"{name}{ext}"
        return Path(plot_dir) / fname

    if "angle" in data.columns:
        plot_distributions(
            data=data,
            x="angle",
            row="num_residues" if residues else None,
            row_order=["4 residues", "5 residues", "6 residues"] if residues else None,
            hue="src",
            binwidth=np.pi / 200,
            format_as_dihedral_axis=False,
            xlim=(1.5, 2.5),
            xlabel="Bond angle",
            height=2 if residues else 3,
            aspect=1.5,
            legend_out=False,
            despine=False,
            path=get_path("angle_dist"),
        )
        plot_distributions(
            data=data,
            x="angle",
            row="num_residues" if residues else None,
            row_order=["4 residues", "5 residues", "6 residues"] if residues else None,
            col="angle_label",
            hue="src",
            height=2 if residues else 3,
            aspect=1.4 if residues else 1,
            binwidth=np.pi / 200,
            format_as_dihedral_axis=False,
            xlim=(1.5, 2.5),
            legend_out=False,
            despine=False,
            path=get_path("angles_dists"),
        )

    if "dihedral" in data.columns:
        plot_distributions(
            data=data,
            x="dihedral",
            row="num_residues" if residues else None,
            row_order=["4 residues", "5 residues", "6 residues"] if residues else None,
            hue="src",
            binwidth=2 * np.pi / 60,
            xlabel="Dihedral angle",
            height=2 if residues else 3,
            aspect=1.5,
            legend_out=False,
            despine=False,
            path=get_path("dihedral_dist"),
        )
        plot_distributions(
            data=data,
            x="dihedral",
            row="num_residues" if residues else None,
            row_order=["4 residues", "5 residues", "6 residues"] if residues else None,
            col="dihedral_label",
            hue="src",
            binwidth=2 * np.pi / 60,
            height=2 if residues else 3,
            aspect=1.4 if residues else 1,
            legend_out=False,
            despine=False,
            path=get_path("dihedrals_dists"),
        )

def format_facet_grid_dihedral_axis(g: sns.FacetGrid, which: Literal["x", "y"] = "x") -> None:
    lim = (-np.pi, np.pi)
    ticks = [-np.pi, -np.pi / 2, 0, np.pi / 2, np.pi]
    ticklabels = [r"-$\pi$", r"-$\pi/2$", 0, r"$\pi/2$", r"$\pi$"]
    g.set(**{f"{which}lim": lim, f"{which}ticks": ticks, f"{which}ticklabels": ticklabels})

def hexbin(
    x: np.ndarray,
    y: np.ndarray,
    color: Optional[Union[str, Tuple[float, float, float]]] = None,
    gridsize: int = 50,
    bins: Union[Literal["log"], int, Sequence[float]] = "log",
    **kwargs,
):
    cmap = kwargs.pop("cmap", None)
    if cmap is None and color is not None:
        cmap = sns.light_palette(color, as_cmap=True)
    plt.hexbin(x, y, gridsize=gridsize, bins=bins, cmap=cmap, **kwargs)

def density_scatter(
    x: Union[np.ndarray, pd.Series],
    y: Union[np.ndarray, pd.Series],
    ax: Optional[mpl.axes.Axes] = None,
    bins: Tuple[int, int] = (500, 500),
    color: Optional[Union[str, Tuple[float, float, float]]] = None,
    norm: ImageNormalize = ImageNormalize(vmin=0, vmax=1, stretch=LogStretch()),
    **kwargs,
) -> mpl.axes.Axes:
    # https://stackoverflow.com/questions/20105364/how-can-i-make-a-scatter-plot-colored-by-density-in-matplotlib
    if ax is None:
        ax = plt.gca()

    x = np.asarray(x)
    y = np.asarray(y)

    hist, xedges, yedges = np.histogram2d(x, y, bins=bins, density=True)
    points = (0.5 * (xedges[1:] + xedges[:-1]), 0.5 * (yedges[1:] + yedges[:-1]))
    points, hist = augment_with_periodic_bc(points, hist, domain=(2 * np.pi, 2 * np.pi))
    z = interpolate.interpn(
        points,
        hist,
        np.vstack([x, y]).T,
        method="splinef2d",
        bounds_error=False,
        fill_value=0,
    )

    # Sort the points by density, so that the densest points are plotted last
    idx = z.argsort()
    x, y, z = x[idx], y[idx], z[idx]

    cmap = kwargs.pop("cmap", None)
    if cmap is None and color is not None:
        cmap = sns.light_palette(color, as_cmap=True)

    ax.scatter(x, y, c=z, cmap=cmap, norm=norm, **kwargs)
    return ax

def augment_with_periodic_bc(
    points: Tuple[np.ndarray, ...],
    values: np.ndarray,
    domain: Optional[Union[float, Sequence[float]]] = None,
) -> Tuple[Tuple[np.ndarray, ...], np.ndarray]:
    """Augment the data to create periodic boundary conditions.

    Parameters
    ----------
    points : tuple of ndarray of float, with shapes (m1, ), ..., (mn, )
        The points defining the regular grid in n dimensions.
    values : array_like, shape (m1, ..., mn, ...)
        The data on the regular grid in n dimensions.
    domain : float or None or array_like of shape (n, )
        The size of the domain along each of the n dimensions
        or a uniform domain size along all dimensions if a
        scalar. Using None specifies aperiodic boundary conditions.

    Returns
    -------
    points : tuple of ndarray of float, with shapes (m1, ), ..., (mn, )
        The points defining the regular grid in n dimensions with
        periodic boundary conditions.
    values : array_like, shape (m1, ..., mn, ...)
        The data on the regular grid in n dimensions with periodic
        boundary conditions.
    """
    # https://stackoverflow.com/questions/25087111/2d-interpolation-with-periodic-boundary-conditions
    # Validate the domain argument
    n = len(points)
    if np.ndim(domain) == 0:
        domain = [domain] * n
    if np.shape(domain) != (n,):
        raise ValueError("`domain` must be a scalar or have the same " "length as `points`")

    # Pre- and append repeated points
    points = [
        x if d is None else np.concatenate([x - d, x, x + d]) for x, d in zip(points, domain)
    ]

    # Tile the values as necessary
    reps = [1 if d is None else 3 for d in domain]
    values = np.tile(values, reps)

    return points, values


from aocd.models import Puzzle

p = Puzzle(year=2021, day=3)

input = [ x[0] for x in [l.strip().split(" ") for l in p.input_data.split("\n")]]

calcs = [0] * len(input[0])
for i in input:
    for x in range(len(input[0])):
        calcs[x] += 1 if int(i[x]) == 1 else -1

oxygen = [x for x in input]
scrubber = [x for x in input]

for x in range(len(input[0])):
    if len(oxygen) > 1:
        oxygen = [y for y in oxygen if y[x] == str(1 if sum([1 if y == '1' else -1 for y in [z[x] for z in oxygen] ]) >= 0 else 0)]
    if len(scrubber) > 1:
        scrubber = [y for y in scrubber if y[x] == str(0 if sum([1 if y == '1' else -1 for y in [z[x] for z in scrubber] ]) >= 0 else 1)]

gamma = int(''.join('1' if x < 0 else '0' for x in calcs), 2)
epsilon = int(''.join('1' if x > 0 else '0' for x in calcs), 2)

print(gamma, epsilon, gamma * epsilon)
print(int(str(oxygen[0]), 2), int(str(scrubber[0]), 2), int(str(oxygen[0]), 2) * int(str(scrubber[0]), 2))


import sys
class NativeDictionary:
    def __init__(self, sz):
        self.size = sz
        self.slots = [None] * self.size
        self.values = [None] * self.size

    def hash_fun(self, key):
        id = sys.getsizeof(key)
        for i in range(self.size):
            if self.slots[i] is not None:
                idx_of_slot = sys.getsizeof(self.slots[i])
                id =  id + idx_of_slot
        id = id % self.size
        return id

    def is_key(self, key):
        if key in self.values:
            return True
        else:
            return False
         # возвращает True если ключ имеется,
         # иначе False
    def put(self, key, value):
        if key in self.values:
            for i in range(self.size):
                if self.values[i] == key:
                    self.slots[i] = value
                    break
        else:
            id_key = self.hash_fun(key)
            if self.values[id_key] is not None:
                for i in range(1,self.size):
                    id_key = id_key + (i * self.hash_fun(key))
                    id_key = id_key % self.size
                    if self.values[id_key] is None:
                        break
            if self.values[id_key] is not None:
                for i in range(self.size):
                    if self.values[i] is None:
                        id_key = i
                        break
            self.values[id_key] = key
            self.slots[id_key] = value

    def get(self, key):
        if self.is_key(key) is True:
            for i in range(self.size):
                if self.values[i] == key:
                    return self.slots[i]
        else:
            return None
         # возвращает value для key,
         # или None если ключ не найден


import sys
import toml

# ===========================================================================

INDENT_LEVEL = 4

TERM_TO_HEX = {}
TERM_TO_COLOR = {}

def parse_colors(colors):
    """ not happy with this, but it works """
    for name, values in colors.items():
        for _type in values:
            for i, code in enumerate(values["hex"]):
                c_name = name
                h_code = code
                t_color = values["term"][i]

                if code[0] == "*":
                    c_name = "Dark" + c_name
                    h_code = h_code[1:]

                TERM_TO_HEX[int(t_color)] = f"#{h_code}"
                TERM_TO_COLOR[int(t_color)] = c_name

def to_hex(color):
    if color == -1 or color == 'NONE':
        return 'NONE'

    try:
        return TERM_TO_HEX[color]
    except KeyError as err:
        print(f"Invalid color '{color}'!")
        sys.exit(-1)

def to_gui(color):
    if color == -1 or color == 'NONE':
        return 'NONE'

    try:
        return TERM_TO_COLOR[color]
    except KeyError as err:
        print(f"Invalid color '{color}'!")
        sys.exit(-1)

def convert_theme_to_vimscript(name, theme):
    """
    Takes a name (string) and a theme (dict) and returns valid vimscript theme
    code (string).
    """
    ws_indent = 0
    vimscript = []
    colors_gui = []
    colors_term = []

    for ident, values in theme.items():
        flags = None
        if values["term"] != -1:
            flags = ','.join(values["term"])

        cterm = 'NONE' if not flags else flags
        ctermfg = 'NONE' if values["fg"] == -1 else values["fg"]
        ctermbg = 'NONE' if values["bg"] == -1 else values["bg"]
        gui = cterm
        guifg = to_hex(ctermfg)
        guibg = to_hex(ctermbg)

        colors_gui.append(f"hi {ident} cterm={cterm} ctermfg={ctermfg} ctermbg={ctermbg} gui={gui} guifg={guifg} guibg={guibg}")
        colors_term.append(f"hi {ident} cterm={cterm} ctermfg={to_gui(ctermfg)} ctermbg={to_gui(ctermbg)}")

    vimscript.append(f"if s:main_color == '{name}'")
    ws_indent += INDENT_LEVEL

    vimscript.append(f"{' ' * ws_indent}if has('gui_running') || &t_Co == 256")
    ws_indent += INDENT_LEVEL

    vimscript.append("\n".join([f"{' ' * ws_indent}{line}" for line in colors_gui]))
    ws_indent -= INDENT_LEVEL

    vimscript.append(f"{' ' * ws_indent}else")
    ws_indent += INDENT_LEVEL

    vimscript.append("\n".join([f"{' ' * ws_indent}{line}" for line in colors_term]))
    ws_indent -= INDENT_LEVEL

    vimscript.append(f"{' ' * ws_indent}endif")
    ws_indent -= INDENT_LEVEL
    vimscript.append(f"{' ' * ws_indent}endif\n")

    return "\n".join(vimscript)

def convert_highlights_to_vimscript(highlights):
    """
    Takes a highlights dict and returns valid vimscript syntax highlighting
    code (string).
    """
    vimscript = []

    for ident, value_dict in highlights.items():
        for scope in value_dict:
            vimscript.append(f"highlight! link {scope} {ident}")

    return "\n".join(vimscript)

def combine_theme_with_base(base, theme):
    """
    Returns a dict with the combined values of base (dict) and theme (dict).
    Theme takes higher precedence and overwrites any values in base.
    """
    new_theme = base.copy()

    for key, value in theme.items():
        new_theme[key] = value

    return new_theme

def file_start(name, version):
    return f"""\
"        Name: {name} ({version})
"     Creator: Judah Caruso Rodriguez <judah@tuta.io>
"     License: GNU General Public License v2.0 (see: LICENSE)
"  Repository: https://github.com/kyoto-shift/film-noir
" Forked From: Andreas van Cranenburgh [vim-256noir] <andreas@unstable.nl>

" Description:
"   A minimal vim colorscheme, focusing on clarity and simplicity. Based off of the
"   colorscheme 'vim-256noir' by Andreas van Cranenburgh <https://github.com/andreasvc/vim-256noir>

highlight clear
set background=dark
if version > 580
    if exists('syntax_on')
        syntax reset
    endif
endif

let s:main_color = get(g:, 'film_noir_color', 'blue')
let g:colors_name = 'film_noir'
"""

def main():
    config_file = toml.load("config.toml")
    parse_colors(config_file["Theme"]["Colors"])

    theme_red = combine_theme_with_base(config_file["Theme"]["Base"], config_file["Theme"]["Red"])
    theme_green = combine_theme_with_base(config_file["Theme"]["Base"], config_file["Theme"]["Green"])
    theme_blue = combine_theme_with_base(config_file["Theme"]["Base"], config_file["Theme"]["Blue"])

    print(file_start(config_file["Information"]["Name"], config_file["Information"]["Version"]))
    print(convert_theme_to_vimscript("red", theme_red))
    print(convert_theme_to_vimscript("green", theme_green))
    print(convert_theme_to_vimscript("blue", theme_blue))
    print(convert_highlights_to_vimscript(config_file["Theme"]["Highlights"]))

if __name__ == "__main__":
    main()


from unittest import TestCase
from sqlalchemy import create_engine, text
from database_queue import MssqlQueue
from config import database_config, queue_config, MssqlQueueConfig, MssqlDatabaseConfig

class TestMssqlQueue(TestCase):
    def setUp(self):
        assert isinstance(database_config, MssqlDatabaseConfig)
        _config = {
            'name': f't_{queue_config.name}',
            'message_type': f't_{queue_config.message_type}',
            'service': f't_{queue_config.service}',
            'contract': f't_{queue_config.contract}'
        }
        self.config = MssqlQueueConfig(**_config)
        self.db_engine = create_engine(database_config.uri)

        sql_create_message_type = text(
            f"CREATE MESSAGE TYPE [{self.config.message_type}] VALIDATION = NONE;"
        )
        sql_create_contract = text(
            f"CREATE CONTRACT [{self.config.contract}] ([{self.config.message_type}] SENT BY INITIATOR);"
        )
        sql_create_queue = text(
            f"CREATE QUEUE {self.config.name} WITH STATUS = ON,RETENTION = OFF,POISON_MESSAGE_HANDLING (STATUS = OFF);"
        )
        sql_create_service = text(
            f"CREATE SERVICE [{self.config.service}] ON QUEUE {self.config.name}([{self.config.contract}]);"
        )
        conn = self.db_engine.connect()
        trans = conn.begin()
        try:
            conn.execute(sql_create_message_type)
            conn.execute(sql_create_contract)
            conn.execute(sql_create_queue)
            conn.execute(sql_create_service)
        except Exception as e:
            trans.rollback()
            raise e
        else:
            trans.commit()
        finally:
            conn.close()

    def tearDown(self):
        sql_drop_message_type = text(
            f"IF EXISTS (SELECT * FROM sys.service_message_types WHERE name = N'{self.config.message_type}') DROP MESSAGE TYPE [{self.config.message_type}]"
        )
        sql_drop_contract = text(
            f"IF EXISTS (SELECT * FROM sys.service_contracts WHERE name = N'{self.config.contract}') DROP CONTRACT [{self.config.contract}]"
        )
        sql_drop_queue = text(
            f"IF EXISTS (SELECT * FROM sys.service_queues WHERE name = N'{self.config.name}') DROP QUEUE [dbo].[{self.config.name}]"
        )
        sql_drop_service = text(
            f"IF EXISTS (SELECT * FROM sys.services WHERE name = N'{self.config.service}') DROP SERVICE [{self.config.service}]"
        )
        conn = self.db_engine.connect()
        trans = conn.begin()
        try:
            conn.execute(sql_drop_service)
            conn.execute(sql_drop_queue)
            conn.execute(sql_drop_contract)
            conn.execute(sql_drop_message_type)
        except Exception as e:
            trans.rollback()
            raise e
        else:
            trans.commit()
        finally:
            conn.close()

    def test_dequeue_message(self):

        queue = MssqlQueue(
            engine=self.db_engine,
            config=self.config)
        queue.enqueue_message('queue message test from python 测试')
        message = queue.dequeue_message()
        self.assertEqual(message.payload, 'queue message test from python 测试')


# Validate Input: https://stackabuse.com/flask-form-validation-with-flask-wtf/
# prepared statement:  in flask
# Parameterized Query avoid sql injection

# TODO : Parameterized Query avoid sql injection
#query = """Update employee set Salary = %s where id = %s"""
# https://pynative.com/python-mysql-execute-parameterized-query-using-prepared-statement/
#tuple1 = (8000, 5)
#cursor.execute(query, tuple1)

# DONE: ABLE to give input text containing ' and " buy replacing with ‘ and “
# TODO: Need when reading need to replace with ' and "

import sys
import sqlite3

def get_create_table_query(table_name, **kwargs):
    query = "CREATE TABLE IF NOT EXISTS {} (".format(table_name)
    comma = ', '
    for key, value in kwargs.items():
        query = query + key + ' ' + value + comma
    query = query.rstrip(comma) + ");"
    return query

# get_create_table_query('store', item='TEXT', quantity='INTEGER', price='REAL')
        # CREATE TABLE IF NOT EXISTS store (item TEXT, quantity INTEGER, price REAL)

def get_insert_query(table_name,**kwargs):
    comma = r', '
    Entry_Field =   ', '.join(list(kwargs.keys()))
    Entry_Value = ''

    for key, value in kwargs.items():
        if isinstance(value, str): # type(value) == 'str':
            value=value.replace("'",'‘') # remove any confusion in query you can re-cover the data when read query replace with ' or "
            value=value.replace('"','“') # remove any confusion in query
            Entry_Value = Entry_Value + """'{}'{}""".format(str(value),comma)
        else:
            Entry_Value = Entry_Value + """{}{}""".format(str(value),comma)
    Entry_Value = Entry_Value.rstrip(comma)

    query = """INSERT INTO {} ({}) VALUES ({});""".format(table_name,Entry_Field, Entry_Value)
    return query

# get_insert_query('Song_Index' ,song_name = 'Nector of Instruction', song_short_name ='noi', sloka_statues=1)
        # >>>  "INSERT INTO Song_Index (song_name, song_short_name, sloka_statues) VALUES ('Nector of Instruction', 'noi', 1);"

def get_read_query(table_name, *args, **kwargs):
    if len(args) == 0:
        query = "SELECT * FROM {}".format(table_name)
    else:
        # print(', '.join(args))
        query = "SELECT {} FROM {}".format(', '.join(args), table_name)

    if len(kwargs) != 0:
        cond_query=''
        for key, value in kwargs.items():
            if isinstance(value, str): # type(value) == 'str':
                cond_query =  """{} {}='{}'{} """.format(cond_query, key,kwargs[key],' and')
            else:
                cond_query =  """{} {}={}{} """.format(cond_query, key,kwargs[key],' and')
        cond_query = cond_query.rstrip(' and')
        query = query + ' WHERE ' + cond_query + ';'
    else:
        query += ';'

    # print('get_read_query:' ,query)
    return query

# get_read_query('temp' )  # >>> SELECT * FROM temp;

# get_read_query('mySong', *['song_idx', 'slokas_no', 'sloka_hindi','slokas_id', 'sloka_eng'])
        # >>> SELECT song_idx, slokas_no, sloka_hindi, slokas_id, sloka_eng FROM mySong;

# get_read_query('mySong', *['song_idx', 'slokas_no', 'sloka_hindi','slokas_id', 'sloka_eng'], song_idx =4 , slokas_id=1)
        # >>> SELECT song_idx, slokas_no, sloka_hindi, slokas_id, sloka_eng FROM mySong WHEN  song_idx=4 and  slokas_id=1;

def get_update_query(table_name, *args, **kwargs):
    query = "UPDATE {} SET ".format(table_name)

    if len(args) == 0:
        last_key = list(kwargs.keys())[-1]
        if isinstance(kwargs[last_key], str):
            cond_query = " WHERE {}='{}'".format(last_key, kwargs[last_key])
        else:
            cond_query = " WHERE {}={}".format(last_key, kwargs[last_key])
        del kwargs[last_key]
    else:

        cond_query = " WHERE "
        for key in args:
            if isinstance(kwargs[key], str):
                cond_query =  """{} {}='{}'{} """.format(cond_query, key,kwargs[key],' and')
            else:
                cond_query =  """{} {}={}{} """.format(cond_query, key,kwargs[key],' and')
            del kwargs[key]
        cond_query = cond_query.rstrip(' and')

    comma = ', '
    for key, value in kwargs.items():
        if isinstance(value, str):
            value=value.replace("'",'‘') # remove any confusion in query you can re-cover the data when read query replace with ' or "
            value=value.replace('"','“') # remove any confusion in query
            query =  """{} {}='{}'{} """.format(query, key,value,comma)  #  query + str(key) + '=' + str(value) + comma
        else:
            query =  """{} {}={}{} """.format(query, key,str(value),comma)

    query = query.rstrip(comma)

    query += cond_query

    return query

# get_update_query('store', quantity=10, price=15, item='indian mango')
        # UPDATE store SET quantity=10, price=15 WHERE item='indian mango'
# get_update_query('store', quantity=10, price=15, item=10)
        # UPDATE store SET quantity=10, price=15 WHERE item=10

def get_delete_query(table_name, **kwargs):
    # if len(kwargs) > 1:
    cond_query = ""
    for key, value in kwargs.items():
        if isinstance(value, str): # type(value) == 'str':
            cond_query = cond_query + """{}='{}'{}""".format(key, str(value),' and ')
        else:
            cond_query = cond_query + """{}={}{}""".format(key, str(value),' and ')
    cond_query = cond_query.rstrip(' and ')

    # table_index = list(kwargs.keys())[0]
    query = "DELETE FROM {} WHERE {};".format(table_name, cond_query )
    # print(query)
    return query

# get_delete_query('Song', song_idx=1,sloka_no = 5)
    # >>> 'DELETE FROM Song WHERE song_idx=1 and sloka_no=5;'

class SqliteModel():
    def __init__(self,db_path,table_name):
        self.db_path = db_path
        self.table_name = table_name
        self.db_connect = sqlite3.connect(db_path) # OperationalError: database is locked may occur to reduce try  <db.connections.close_all()>
                                                # https://www.geeksforgeeks.org/how-to-list-tables-using-sqlite3-in-python/?ref=lbp

    def create_table(self, **kwargs):
        # self.db_connect = sqlite3.connect(db_path)
        self.db_cursor = self.db_connect.cursor()
        query = get_create_table_query(self.table_name, **kwargs)
        try :
            self.db_cursor.execute(query)
            self.db_connect.commit()
            # auto_increment and delete on cascade https://stackoverflow.com/questions/29037793/sqlite-integrityerror-unique-constraint-failed
            self.db_cursor.close()
            # self.db_connect.close()
        except sqlite3.Error as e:
            print('SQLite error: %s' % (' '.join(er.args)))
            print("Exception class is: ", er.__class__)
            print('SQLite traceback: ')
            exc_type, exc_value, exc_tb = sys.exc_info()

        finally:
            self.db_cursor.close()
            print('Table : {} Created Successful !'.format(self.table_name))

    def create_entry(self, **kwargs):
        query = get_insert_query(self.table_name,**kwargs)
        self.db_cursor = self.db_connect.cursor()
        # print(query)
        try :
            self.db_cursor.execute(query)
            self.db_connect.commit()
        except sqlite3.IntegrityError as e:
            # print('Exception: {}'.format(e))   # >>>  Exception: UNIQUE constraint failed: SongIndex.song_short_name
            print('Can\'t Create new Entry! Already Existing Entry!',' '.join(e.args))                      # >>> ('UNIQUE constraint failed: SongIndex.song_short_name',)
            # print('Exception: %s' % (' '.join(e.args)))   # >>> UNIQUE constraint failed: SongIndex.song_short_name
            # print("Exception class is: ", e.__class__)  # >>> Exception class is:  <class 'sqlite3.IntegrityError'>

            # print('SQLite traceback: ')
            # exc_type, exc_value, exc_tb = sys.exc_info()
            # print(sys.exc_info())
                # >>> (<class 'sqlite3.IntegrityError'>, IntegrityError('UNIQUE constraint failed: SongIndex.song_short_name'), <traceback object at 0x7fce51c32b80>)
            # print(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")
                 # >>> IntegrityError at line 154 of /media/karthik/myVolume/workspace/workspae_vedabase/slokabase/SqliteModel.py: UNIQUE constraint failed: SongIndex.song_short_name

        finally:
            self.db_cursor.close()

    def read_entry(self, *args, **kwargs):
        # query = "SELECT * FROM {};".format(self.table_name)
        query = get_read_query(self.table_name, *args,**kwargs)
        # print(query)
        self.db_cursor = self.db_connect.cursor()
        try :
            self.db_cursor.execute(query)
            columns = [column[0] for column in self.db_cursor.description]
            data = [dict(zip(columns, row)) for row in self.db_cursor.fetchall()]
            # print(data)
            # rows = self.db_cursor.fetchall()
            # for row in rows:
            #     print(row)

        except sqlite3.Error as e:
            print('Exception: {}'.format(e))
        finally:
            self.db_cursor.close()
        return data

    def update_entry(self,*args, **kwargs):
        query = get_update_query(self.table_name,*args,**kwargs)
        self.db_cursor = self.db_connect.cursor()
        #print(query)
        try :
            self.db_cursor.execute(query)
            self.db_connect.commit()
        except sqlite3.Error as e:
            print('Exception: {}'.format(e))

        finally:
            self.db_cursor.close()

    def delete_entry(self, **kwargs):
        self.db_cursor = self.db_connect.cursor()
        query = get_delete_query(self.table_name, **kwargs)
        print(query)
        try :
            self.db_cursor.execute(query)
            self.db_connect.commit()
        except sqlite3.Error as e:
            print('Exception: {}'.format(e))

        finally:
            self.db_cursor.close()

    def delete_table(self):
        self.db_cursor = self.db_connect.cursor()
        query = 'DROP TABLE IF EXISTS {};'.format(self.table_name)
        print(query)
        try :
            self.db_cursor.execute(query)
            self.db_connect.commit()
        except sqlite3.Error as e:
            print('Exception: {}'.format(e))

        finally:
            self.db_cursor.close()

    def db_close(self):
        self.db_connect.close()

    def __del__( self):
        #  print('Closed Connection to db')
         self.db_connect.close()