import numpy as np
import matplotlib.pyplot as plt
from tqdm import tqdm
import arc as arc

import numpy as np
import scipy.constants as consts
from scipy.stats import maxwell
import os, sys
from functools import partialmethod

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

class HiddenPrints:
    """Class for suppressing stdout (print) for some part of the code"""
    def __enter__(self):
        self._original_stdout = sys.stdout
        sys.stdout = open(os.devnull, 'w')

    def __exit__(self):
        sys.stdout.close()
        sys.stdout = self._original_stdout

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

class LaserCooling:
    """ Class representation of 1D Optical Molasses laser cooling of Rubidium-87 in the
        |n1 = 5, l1 = 1, j1 = 3/2> to |n2 = 5, l2= 0, j2 = 1/2> transition """

    def __init__(self, initial_temperature = 0.001, nr_particles = 1000, I_of_I_sat = 1/100, dB_dx = 0):

        assert type(nr_particles) is int,         f"Nr_particles given as {type(nr_particles)}, but should be {int}."
        assert nr_particles >= 1,                 f"Nr_particles should be at least 1."
        assert initial_temperature  >  0,         f"Initial_temperature has to be > 0."
        assert I_of_I_sat < 1 and I_of_I_sat > 0, f"I_of_I_sat should be 0 < I_of_I_sat < 1."
        assert dB_dx >= 0,                        f"dB_dx should be >= 0."

        self.saturation_fraction = I_of_I_sat           # Fraction of saturation intensity used in laser.
        self.temperature         = initial_temperature  # In units of [K]
        self.nr_particles        = nr_particles
        self.magnetic_gradient   = dB_dx

        self.atom       = self.set_atom()
        self.mass       = self.set_mass()
        self.gamma      = self.set_gamma()
        self.omega_0    = self.set_omega0()

        self.initial_speeds   = self.set_initial_speeds()
        self.initial_positions = self.set_initial_position()

    def set_atom(self):
        """ Function for setting the mass of the Rubidium 87 atom

        Returns:
        --------
            atom: instance of arc.alkali_atom_data.Rubidium87 class

        """
        atom = arc.alkali_atom_data.Rubidium87()
        return atom

    def set_mass(self) -> float:
        """ Function for setting the mass of the Rubidium 87 atom

        Returns:
        --------
            mass: float

        """
        mass = arc.alkali_atom_data.Rubidium87.mass
        return mass

    def set_omega0(self) -> float:
        """ Function for computing the angular transition resonance frequncy ω0
        of the chosen transition

        Returns:
        --------
            omega_0: float

        """
        omega_0 = 2 * np.pi * self.atom.getTransitionFrequency(n1 = 5, l1= 0, j1 = 0.5, n2 = 5, l2 = 1, j2 = 3/2)

        return omega_0

    def set_gamma(self) -> float:
        """ Function for computing the natural linewidth Γ

        Returns:
        --------
            Natural_linewidth: float
        """
        Transition_rate   = self.atom.getTransitionRate(n2 = 5, l2= 0, j2 = 0.5, n1 = 5, l1 = 1, j1 = 3/2)
        Lifetime          = 1 / Transition_rate
        Natural_linewidth = 1 / (2 * np.pi * Lifetime) * 2 * np.pi
        return Natural_linewidth

    def set_initial_speeds(self) -> np.ndarray:
        """ Function for sampling initial speeds for the atoms
        from the maxwell-boltzman distribution. Here this is achieved
        by means of the 'Inverse CDF sampling' method where sampling
        N points from a given PDF is similar to evaluating its inverse CDF
        on N uniformly distributed points (in Uniform(0,1)).

        Returns:
        --------
            speeds: np.ndarray of shape (nr_particles,) containing floats
        """
        PARENT_SAMPLE_SIZE = 1000000
        u                  = np.random.uniform(low = 0, high = 1, size = PARENT_SAMPLE_SIZE)
        scale_factor       = np.sqrt(consts.k * self.temperature / (self.mass))      # sqrt(kT/m)
        speeds             = maxwell.ppf(q = u, scale = scale_factor)                # ppf is inverse cdf in scipy
        return speeds[:self.nr_particles]

    def set_initial_position(self) -> np.ndarray:
        """ Function for sampling initial positions of the atoms.
        here it is simply assumed that the atoms are gaussianly
        distributed around 0 with som chosen standard deviation.

        Returns:
        --------
            positions: np.ndarray of shape (nr_particles,) containing floats.
        """
        standard_deviation = 0.1
        expectation_value  = 0.0
        positions = np.random.normal(loc = expectation_value, scale = standard_deviation, size=self.nr_particles)
        return positions

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

class Simulation:
    """Class representation of a Monte Carlo simulation of given laser cooling setup."""

    def __init__(self, MyLaserCooling, stepsize = 0.001, tmax = 1, with_emission = True):

        assert stepsize <= 0.001 and stepsize > 0.0, f"Stepsize should be:  0 < stepsize < 0.001 ."
        assert tmax >= 10 * stepsize,                f"Tmax should be:  Tmax >= 10 * stepsize for any meaningfull simuation."
        assert type(with_emission) is bool,          f"With_emission given as {type(with_emission)}, but should be {bool}. "

        self.with_emission   = with_emission
        self.stepsize        = stepsize         # In units of [s]
        self.tmax            = tmax             # In units of [s]

        self.MyLaserCooling  = MyLaserCooling

        self.beta            = self.set_beta()

        self.ts                                             = None
        self.xs_with_emission, self.vxs_with_emission       = None, None
        self.xs_without_emission, self.vxs_without_emission = None, None

        self.Es_with_emission, self.Es_without_emission     = None, None
        self.Temperature_with_emission                      = None
        self.Temperature_without_emission                   = None

        self.omegas                                         = None
        self.multiple_temperatures_without_emission         = None
        self.multiple_temperatures_with_emission            = None

    def temperature_dependency(self,detuning) -> int or float:
        """ Function that computes the temperature for some chosen detuning
            accoring to eq. (9.27) in Christopher J. Foot - Atomic Physics, Oxford University Press 2005

        Parameters:
        -----------
            detuning: int or float or
                      1D np.ndarray of floats or 1D np.ndarray of ints

        Returns:
        --------
            temperature: same type as given detuning.

        """
        gamma       = self.MyLaserCooling.gamma
        temperature = (consts.hbar * gamma) / (4 * consts.k) * (1 + (2 * detuning / gamma)**2) / (-2 * detuning / gamma)
        return temperature

    def set_beta(self) -> float:
        """ Function for calculating the beta parameter from
            eq. (9.31) in Christopher J. Foot - Atomic Physics, Oxford University Press 2005

        Returns:
        --------

        """
        g    = self.MyLaserCooling.atom.getLandegjExact(s = 0.5, j = 1/2, l = 0)
        U_B  = consts.e * consts.hbar/(2 * consts.electron_mass)

        beta = (g * U_B / consts.hbar) * self.MyLaserCooling.magnetic_gradient
        return beta

    def nr_scattered_photons(self, dt, omega, seed) -> int:
        """ Function for computing a realistic estimate of the actual number
            scattered photons by first calculating the expectation value <N>
            according to eq. (9.4) in Christopher J. Foot - Atomic Physics, Oxford University Press 2005
            and the drawing the 'actual number' as a sample from a poissonian distributed around <N>.

        Parameters:
        -----------
            dt    : float or int - the time over which <N> is calculted

            omega : float or int - ω in δ = ω - ω0

            seed  : int - for insuring difference in the return of
                  the random functions for each call

        Returns:
        --------
            actual_nr : int - the number of scattered photons during dt.
        """
        I_Isat, gamma  = self.MyLaserCooling.saturation_fraction, self.MyLaserCooling.gamma

        expectation_nr = dt * (gamma / 2) * (I_Isat) / (1 + I_Isat + 4 * (omega - self.MyLaserCooling.omega_0)**2 / gamma**2)
        generator      = np.random.default_rng(seed=seed)
        actual_nr      = generator.poisson(lam=expectation_nr)
        return actual_nr

    def spherical_sampling(self,nr_photons) -> np.ndarray or float:
        """ Function for sampling the amount that nr_photons
            contributes with change in momentum along x-axis
            under the assumption of isotropic emission, i.e.
            that the photons ar uniformly emitted through a
            sphere.

            This is done first by means of 'Inverse CDF sampling'
            where sampling N points from a given PDF is similar to
            evaluating its inverse CDF on N uniformly distributed
            points (in Uniform(0,1)).

        Parameters:
        -----------
            nr_photons: int - the number of photons emitted.

        Returns:
        --------
            x: np.ndarray of shape (nr_photons,) containing floats
               or float
        """
        theta = np.random.uniform(0,np.pi,nr_photons)
        phi   = np.arccos(1 - 2 * np.random.uniform(0,1,nr_photons)) # This is the inverse CDF
        x     = np.sin(phi) * np.cos(theta)                          # Transforming to cartesian coordinates
        return x

    def set_wavenumber(self, omega) -> float:
        """ Function for computing the wavenumber 'k'
        of some wave, given its angular frequency.

        Parameters:
        -----------
            omega: float

        Returns:
        --------
            k: float
        """
        k = omega/consts.c
        return k

    def set_alpha(self, omega) -> float:
        """ Function for computing the alpha parameter according to
            eq. (9.17) in Christopher J. Foot - Atomic Physics, Oxford University Press 2005.

        Parameters:
        -----------
            omega: float

        Returns:
        --------
            alpha: float

        """
        omega_0    = self.MyLaserCooling.omega_0
        detuning   = omega - omega_0
        wavenumber = self.set_wavenumber(omega)
        gamma      = self.MyLaserCooling.gamma
        I_Isat     = self.MyLaserCooling.saturation_fraction

        alpha = 4. * consts.hbar * wavenumber**2 * I_Isat * (-2 * detuning / gamma)/(1 + (2 * detuning/gamma)**2)**2
        return alpha

    def simulate_one_detuning(self,omega):
        """ Function for simulating the laser cooling for a single detuning.
            stores results in class attributes seen in constructor.

        Parameters:
        -----------
            omega: float
        """
        alpha = self.set_alpha(omega=omega)
        k     = self.set_wavenumber(omega=omega)

        ts = None
        xs_with_emission, vxs_with_emission       = [], []
        xs_without_emission, vxs_without_emission = [], []

        print("-"*10+" Simulating cooling process "+"-"*10)

        for i in tqdm(range(len(self.MyLaserCooling.initial_speeds))):
            ts_i = [0]
            start_x, start_vx = self.MyLaserCooling.initial_positions[i], self.MyLaserCooling.initial_speeds[i]
            xs_i_with_emission, vxs_i_with_emission       = [start_x], [start_vx]
            xs_i_without_emission, vxs_i_without_emission = [start_x], [start_vx]
            time = 0

            while(time <= self.tmax):
                x_with_emission, vx_with_emission       = xs_i_with_emission[-1], vxs_i_with_emission[-1]
                x_without_emission, vx_without_emission = xs_i_without_emission[-1], vxs_i_without_emission[-1]

                step = self.stepsize
                time += step

                if self.with_emission:
                    # Calculating forces - with emission
                    seed1, seed2 = int((i + 1) * 1000 * time),  int(2 * (i + 1) * 1000 * time)
                    nr1_with_emission          = self.nr_scattered_photons(step, omega - k * vx_with_emission, seed1)
                    nr2_with_emission          = self.nr_scattered_photons(step, omega + k * vx_with_emission, seed2)

                    DP_absorbtion_with_emission = consts.hbar * k * (nr1_with_emission - nr2_with_emission)
                    DP_emmission = consts.hbar * k * np.sum(self.spherical_sampling(nr1_with_emission+nr2_with_emission))

                    DP_total_with_emission = DP_absorbtion_with_emission + DP_emmission - alpha * self.beta * x_with_emission * step / k

                # Calculating forces - without emission
                seed1, seed2 = int((i + 1) * 1000 * time),  int(2 * (i + 1) * 1000 * time)
                nr1_without_emission          = self.nr_scattered_photons(step, omega - k * vx_without_emission, seed1)
                nr2_without_emission          = self.nr_scattered_photons(step, omega + k * vx_without_emission, seed2)

                DP_absorbtion_without_emission = consts.hbar * k * (nr1_without_emission - nr2_without_emission)

                DP_total_without_emission = DP_absorbtion_without_emission - alpha * self.beta * x_without_emission * step / k

                # Updating vals
                xs_i_with_emission.append(x_with_emission + step * vx_with_emission)
                vxs_i_with_emission.append(vx_with_emission + DP_total_with_emission / self.MyLaserCooling.mass)

                xs_i_without_emission.append(x_without_emission + step * vx_without_emission)
                vxs_i_without_emission.append(vx_without_emission + DP_total_without_emission / self.MyLaserCooling.mass)

                ts_i.append(time)

            xs_without_emission.append(xs_i_without_emission)
            vxs_without_emission.append(vxs_i_without_emission)

            if self.with_emission:
                xs_with_emission.append(xs_i_with_emission)
                vxs_with_emission.append(vxs_i_with_emission)

            if i == 0:
                ts = ts_i

        self.ts                                             = ts
        self.xs_without_emission, self.vxs_without_emission = xs_without_emission, vxs_without_emission

        if self.with_emission:
            self.xs_with_emission, self.vxs_with_emission   = xs_with_emission, vxs_with_emission

        print("-"*10+" Calculating energies and temperatures "+"-"*10)

        Es_without_emission = np.zeros(len(ts))
        for i in tqdm(range(len(ts))):
            Es_without_emission[i] += np.sum(0.5 * self.MyLaserCooling.mass * (np.array(self.vxs_without_emission)[:,i])**2)
        self.Es_without_emission          = Es_without_emission
        self.Temperature_without_emission = 2 * self.Es_without_emission/(self.MyLaserCooling.nr_particles * consts.k)

        if self.with_emission:
            Es_with_emission = np.zeros(len(ts))
            for i in tqdm(range(len(ts))):
                Es_with_emission[i] += np.sum(0.5*self.MyLaserCooling.mass * (np.array(self.vxs_with_emission)[:,i])**2)
            self.Es_with_emission          = Es_with_emission
            self.Temperature_with_emission = 2 * self.Es_with_emission/(self.MyLaserCooling.nr_particles * consts.k)

    def simulate_multiple_detunings(self,omegas):
        """ Function for doing simulation for multiple values of detuning.
            stores results in class attributes seen in constructor.

        Parameters:
        -----------
            omegas: list of floats or list of ints
                    or np.ndarray of floats or np.ndarray of ints

        """

        self.omegas = omegas

        xs_with_emission, vxs_with_emission       = [], []
        xs_without_emission, vxs_without_emission = [], []

        print("-" * 10 + f" Simulating laser cooling for {len(omegas)} detunings " + 10 * "-")
        with HiddenPrints():
            for idx in tqdm(range(len(omegas))):
                tqdm.__init__ = partialmethod(tqdm.__init__, disable=True)
                self.simulate_one_detuning(omega=omegas[idx])

                xs_with_emission.append(self.xs_with_emission)
                vxs_with_emission.append(self.vxs_with_emission)

                xs_without_emission.append(self.xs_without_emission)
                vxs_without_emission.append(self.vxs_without_emission)
                tqdm.__init__ = partialmethod(tqdm.__init__, disable=False)

        print("-" * 10 + " Calculating energies and corresponding temperatures" + 10 * "-")
        Es_without_emission = []
        for j in tqdm(range(len(vxs_without_emission))):
            Es = np.zeros(len(self.ts))
            for i in range(len(self.ts)):
                Es[i] += np.sum(0.5*self.MyLaserCooling.mass*(np.array(vxs_without_emission[j])[:,i])**2)
            Es_without_emission.append(Es)
        Es_without_emission = np.array(Es_without_emission)

        FRACTION = len(Es_without_emission) // 20 ## Using mean of last 5% of energy vals

        Temperatures_without_emission = []
        for Es in Es_without_emission:
            Temperatures_without_emission.append(2 * np.mean(Es[len(Es) - FRACTION:]) / (self.MyLaserCooling.nr_particles * consts.k))

        self.multiple_temperatures_without_emission = Temperatures_without_emission
        if self.with_emission:
            Es_with_emission = []
            for j in tqdm(range(len(vxs_with_emission))):
                Es = np.zeros(len(self.ts))
                for i in range(len(self.ts)):
                    Es[i] += np.sum(0.5*self.MyLaserCooling.mass*(np.array(vxs_with_emission[j])[:,i])**2)
                Es_with_emission.append(Es)
            Es_with_emission = np.array(Es_with_emission)

            Temperatures_with_emission = []
            for Es in Es_with_emission:
                Temperatures_with_emission.append(2 * np.mean(Es[len(Es) - FRACTION:]) / (self.MyLaserCooling.nr_particles * consts.k))
            self.multiple_temperatures_with_emission = Temperatures_with_emission


import discountpy.shift_scanner as s
from discountpy.motif import *
from discountpy import encode

class MotifSpace:
    """ MotifSpace: create the priority lookup table from which
        priority/rank of each Motif can be accessed easily
    """
    __slots__ = ('width', '_maxMotifs', 'scanner', 'byPriority', 'priorityLookUp')
    width: int
    byPriority: list
    scanner: s.ShiftScanner
    _maxMotifs: int
    priorityLookUp: list

    def __init__(self, byPriority: list):
        self.byPriority = list(byPriority)
        self.width = len(self.byPriority[0])
        self.scanner = s.ShiftScanner(self)
        self._maxMotifs = 4 << (self.width * 2 - 2)
        self.priorityLookUp = [-1]*self._maxMotifs

        for pri, motif in enumerate(self.byPriority):
            self.priorityLookUp[self.motifToInt(motif)] = pri

    def motifToInt(self, m: str) -> int:
        return encode(m)

    def priorityOf(self, mk):
        return self.priorityLookUp[self.motifToInt(mk)]

    def create(self, pattern, pos):
        return Motif(pos, Features(pattern, self.priorityOf(pattern), True))

class _MotifSpace:
    all1mersDNA = ("A", "C", "G", "T")
    all1mersRNA = ("A", "C", "G", "U")

    def motifsOfLength(self, width: int, rna: bool = False) -> iter:
        bases = self.all1mersRNA if rna else self.all1mersDNA

        def generate(prefix, length):
            if (length == 0):
                yield prefix
                return

            for base in bases:
                yield from generate(prefix + base, length-1)

        return generate("", width)

    def fromTemplateWithValidSet(self, template: MotifSpace, validMers: iter) -> MotifSpace:
        validSet = set(validMers)
        return MotifSpace(filter(lambda _: _ in validSet, template.byPriority))


import os
import subprocess

from IPython.core.magic import register_cell_magic
from IPython.display import SVG

__title__ = "iplantuml"
__description__ = "Package which adds a PlantUML cell magic to IPython."
__uri__ = "https://github.com/jbn/iplantuml"
__doc__ = __description__ + " <" + __uri__ + ">"
__license__ = "MIT"
__copyright__ = "Copyright (c) 2017 John Bjorn Nelson"
__version__ = "0.0.5"
__author__ = "John Bjorn Nelson"
__email__ = "jbn@abreka.com"

PLANTUMLPATH = '/usr/local/bin/plantuml.jar'

def plantuml_exec(*file_names, **kwargs):
    """
    Given a list of UML documents, generate corresponding SVG diagrams.

    :param file_names: the filenames of the documents for parsing by PlantUML.
    :param kwargs: optionally `plantuml_path`, indicating where the PlantUML
        jar file resides.
    :return: the path to the generated SVG UML diagram.
    """
    plantuml_path = kwargs.get('plantuml_path', PLANTUMLPATH)

    cmd = ["java",
           "-splash:no",
           "-jar", plantuml_path,
           "-tsvg"] + list(file_names)

    subprocess.check_call(cmd, shell=False, stderr=subprocess.STDOUT)

    return [os.path.splitext(f)[0] + ".svg" for f in file_names]

@register_cell_magic
def plantuml(line, cell):
    """
    Generate and inline the SVG portrayal of the given PlantUML UML spec.

    :param line: if not empty, it is the base file name to give to the
        serialized cell contents and the generated SVG files.
    :param cell: the PlantUML language UML specification.
    :return: a IPython SVG object for the diagram or None given error.
    """
    if line:
        retain, base_name = True, os.path.splitext(line)[0]
    else:
        retain, base_name = False, "tmp"

    uml_path = base_name + ".uml"
    with open(uml_path, 'w') as fp:
        fp.write(cell)

    try:
        svg_name = plantuml_exec(uml_path)[0]
        return SVG(filename=svg_name)
    finally:
        if not retain:
            os.unlink(uml_path)

            svg_path = base_name + ".svg"
            if os.path.exists(svg_path):
                os.unlink(svg_path)


import cv2
from time import sleep

# Load the cascade
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades +  'haarcascade_frontalface_default.xml')

# To use a single image as input
img = cv2.imread("testAI.jpg")

# Convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Detect the faces
faces = face_cascade.detectMultiScale(gray, 1.1, 4)

# Draw the rectangle around each face
for (x, y, w, h) in faces:
    cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)

# Display
cv2.imshow('img', img)

k = cv2.waitKey(0)
cv2.imwrite("AI_proc.jpg",img)


'''
Template module that provides an user with privileges to read the CloudFormation
stack definition. You usually want such an user when doing advanced operations
with Metadata (i.e. using the cfn-init utils)

@author: David Losada Carballo <david@tuxpiper.com>
'''

from _context import stack
from cloudcast.template import *

stack.add_required_capability("CAPABILITY_IAM")

CloudFormationStackUser = Resource(
        "AWS::IAM::User",
        Path="/stackusers/",
        Policies=[{
            "PolicyName": "cfn_user_access",
            "PolicyDocument": {
                "Statement": [{
                    "Effect": "Allow",
                    "Action": "cloudformation:DescribeStackResource",
                    "Resource":"*"
                }]
            }
        }]
    )

CloudFormationStackUserKey = Resource(
        "AWS::IAM::AccessKey",
        Status="Active",
        UserName=CloudFormationStackUser
)


import cmaps
import sys
sys.path.append("lib")
from Taylor_Draw import Figure4wrf

scale,dpi=10,180    #泰勒图的大小，dpi
title='泰勒图示意图'  #图题
title_size,title_y=12,1.03  #标题大小以及高度
r_small, r_big, r_interval=0,1.6,0.25   #半径r的始末以及间隔
tick_size=8
rad_list=[0,0.2,0.4,0.6,0.7,0.8,0.85,0.9,0.95,0.99,1]           #需要显示数值的主要R的值
minor_rad_list=[0,0.1,0.2,0.3,0.4,0.5,0.6,0.65,0.7,0.75,0.8,0.85,0.86,0.87,0.88,0.89,
                0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1]     #需要显示刻度的次要R的值
a_gridtype,a_gridcolor,a_gridwidth=':','blue',0.8     #原点到R的网格线型、颜色、线宽
r_gridtype,r_gridcolor,r_gridwidth=':','green',0.8    #距离r到r的网格线型、颜色、线宽
angle_linewidth,angle_length=0.8,0.02       #R上刻度线的线宽与长度
circle_list=[(0.25,'black','--',0.8),(0.5,'black','--',0.8),
             (0.75,'black','--',0.8),(1,'black','--',0.8)]     #[(半径，颜色，线型，线宽)]
xlabel='Normalized'         #x轴标签的内容
xlabel_pad,xlabel_size=18,8 #x轴标签距离坐标轴的距离与字体大小
anglelabel='COR'            #R上的标签内容
anglelabel_pad,anglelabel_size=1.75,8   #R上标签的距离与字体大小
#画第一个标签的参数
R1,RMSE1=0.85,0.1
marker_type1,marker_size1,marker_color1,label1='o',4.5,'red','Label1'
#画第一个标签的参数
R2,RMSE2=0.97,-0.12
marker_type2,marker_size2,marker_color2,label2='+',4.5,'green','Label2'
#第一个标签上的字
textR1,textr1=0.83,1+0.08   #这里的是标签，不能再输入R与RMSE，要输入极坐标中角度（弧度制）与距离的绝对值
text1,textsize1='Label1',8
#第二个标签上的字
textR2,textr2=0.96,1-0.13
text2,textsize2='Label2',8

#图例
loc='upper right'   #图例位置
labelspacing=1      #图例当中的空格
markerscale=1     #图例标签大小
legend_title="图例"   #图例标题
markerfont,markerfontsize='times',8     #图例中marker的字体与字体大小
titlefont,titlesize='simsun',12  #图例中title的字体与字体大小

path,save_dpi='泰勒图.png',500

fig = Figure4wrf(scale,dpi)
fig.init_draw(title,title_size,title_y)
fig.grid_draw(r_small, r_big, rad_list, minor_rad_list, r_interval,tick_size,a_gridtype,a_gridcolor,a_gridwidth,r_gridtype,r_gridcolor,r_gridwidth,angle_linewidth,angle_length,circle_list)
fig.label_draw(xlabel,xlabel_pad,xlabel_size,anglelabel,anglelabel_pad,anglelabel_size)
fig.marker_draw(R1,RMSE1,marker_type1,marker_size1,marker_color1,label=label1)
fig.marker_draw(R2,RMSE2,marker_type2,marker_size2,marker_color2,label=label2)
fig.text_draw(textR1,textr1,text1,textsize1)
fig.text_draw(textR2,textr2,text2,textsize2)
fig.legend_draw(loc,labelspacing,markerscale,title=legend_title,titlefont=titlefont,titlesize=titlesize,markerfont=markerfont,markerfontsize=markerfontsize)
fig.save_fig(path,save_dpi)
fig.fig_show()


# A Python program to show different ways to create
# Counter
from collections import Counter

# With sequence of items
print(type(Counter([('k') * 2, 'B', 'A', 'B', 'C', 'A', 'B', 'B', 'A', 'C'])))

# with dictionary
print (Counter({'A':3, 'B':5, 'C':2}))

# with keyword arguments
print (Counter(A=3, B=5, C=2))

# Python program to demonstrate that counts in
# Counter can be 0 and negative
from collections import Counter

c1 = Counter(A=4, B=3, C=10)
c2 = Counter(A=10, B=3, C=4)

c1.subtract(c2)
print(c1)
# Python program to demonstrate accessing of
# Counter elements
from collections import Counter

# Create a list
z = ['blue', 'red', 'blue', 'yellow', 'blue', 'red']
col_count = Counter(z)
print(col_count)

col = ['blue','red','yellow','green']

# Here green is not in col_count
# so count of green will be zero
for color in col:
    print (color, col_count[color])


#!/usr/bin/env python
# coding: utf-8

# In[64]:

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error as mae

# In[65]:

data = pd.read_csv('/home/leong/Desktop/concrete_clean.csv')
data.head()

# In[66]:

data.isnull().sum()

# In[67]:

X = data.drop(columns=['StrengthMPa'])
Y = data['StrengthMPa']

# In[68]:

#random_state controls the shuffling of the set selected at random for the split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size = 0.2)

# In[69]:

lin_reg = LinearRegression()
lin_reg.fit(X_train, Y_train)

# In[70]:

#predicting
predictions1 = lin_reg.predict([[445.8, 34.8, 0.1, 123.0, 1.2, 456.9, 213.4, 98, 0.606769]])
predictions1

# In[71]:

predictions2 = lin_reg.predict([[115.8, 24.8, 0.0, 123.0, 1.9, 206.9, 111.4, 15, 0.903369]])
predictions2

# In[72]:

#Mean Square Error
'''measures the average of error squares i.e.
the average squared difference between the estimated values and true value'''

training_data = lin_reg.predict(X_train)
MSE = mean_squared_error(Y_train, training_data)
MSE

# In[76]:

#mean absolute error
'''Mean Absolute Error calculates the average
difference between the calculated values and actual values'''
MAE = mae(Y_train, training_data)
MAE

# In[ ]:

Concrete wall prediction/ML Catchup CA.py


from rest_framework import status
from rest_framework import exceptions
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated

from drf_yasg.utils import swagger_auto_schema

from apps.posts.models import Post, PostLike

class PostLikeId(APIView):
    permission_classes = [IsAuthenticated]

    def get_object(self, pk):
        try:
            post = Post.objects.get(id=pk)
            return post
        except post.DoesNotExist:
            raise exceptions.NotFound

    @swagger_auto_schema(
        operation_description="""
        # post를 좋아요합니다.
        ### - post_id를 path parameter로 받습니다.
        ### - 해당 api를 다시 요청하면 좋아요가 취소됩니다.
        ### - 요청한 포스트가 삭제되었다면 404를 반환합니다.
        """,
    )
    def post(self, request, pk, format=None):
        post = self.get_object(pk)
        if post.is_deleted:
            raise exceptions.NotFound

        post_like, created = PostLike.objects.get_or_create(
            user=request.user,
            post=post,
        )

        if not created:
            post_like.delete()

        return Response(
            {
                "is_liked": created,
            },
            status=status.HTTP_200_OK,
        )


import pandas as pd
import requests
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def get_concelhos_name(id_concelho):
    link = 'https://agendamento.irn.mj.pt/steps/get_concelhos.php?id_distrito={0}'.format(str(id_concelho))
    result = requests.get(link)
    c = result.content
    soup = BeautifulSoup(c)

    options = soup.find_all('option')
    names = {x['value']: x.text for x in options}
    del names['']
    return names

def open_page_and_select_cc(query='cc'):
    DRIVER_PATH = 'data/chromedriver'
    driver = webdriver.Chrome(executable_path=DRIVER_PATH)
    driver.get('https://agendamento.irn.mj.pt/steps/step1.php')

    select_servico = Select(driver.find_element_by_xpath('//*[@id="servico"]'))
    if query == 'cc':
        select_servico.select_by_visible_text('Pedido / Renovação de Cartão de Cidadão')
        delay = 1
        button = WebDriverWait(driver, delay).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="myModal"]/div/div/div[3]/button'))).click()

    elif query == 'passport':
        select_servico.select_by_visible_text('Pedido de Passaporte Electrónico')

    else:
        print ("query is cc or passport")

    return driver

def get_distritos_names():
    driver = open_page_and_select_cc()
    html_source = driver.page_source
    soup = BeautifulSoup(html_source)

    distritos = soup.find_all('select')[1].find_all('option')
    names = {x.text: x['value'] for x in distritos}
    del names['Selecione uma opção']

    driver.close()
    return names

def is_validated(distrito, concelho):
    today = pd.to_datetime('today').strftime("%Y-%m-%d")

    link = 'https://agendamento.irn.mj.pt/steps/get_aval.php?f=checkStep1&ids={0}&idc={1}&data={2}&sab=0'.format(str(distrito),
                                                                                str(concelho),
                                                                                str(today))

    result = requests.get(link)
    c = result.content
    soup = BeautifulSoup(c)

    return soup.text

def get_hours(distritos, query='cc'):
    from selenium.webdriver.support.ui import Select

    driver = open_page_and_select_cc(query)
    distrito_dict = get_distritos_names()
    result = pd.DataFrame()
    for distrito in distritos:
        print ("Distrito: {0}".format(distrito))
        concelhos = get_concelhos_name(distrito_dict[distrito])
        select_distrito = Select(driver.find_element_by_xpath('//*[@id="distrito"]'))
        select_distrito.select_by_visible_text(distrito)

        for concelho_id in concelhos.keys():
            print ("Concelho: {0}".format(concelhos[concelho_id]))
            WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.XPATH, '//*[@id="concelho"]/option[2]')))
            select_concelho = Select(driver.find_element_by_xpath('//*[@id="concelho"]'))
            select_concelho.select_by_value(concelho_id)

            driver.find_element_by_xpath('//*[@id="btnSeguinte"]').click()

            try:
                new_page = WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.XPATH, '//*[@id="divHorario"]/h4')))

                html_source = driver.page_source
                soup = BeautifulSoup(html_source)
                dates = soup.find_all('table')
                dates = [x.text[-10:] for x in dates]

                if len(dates) >= 1:
                    table_row = pd.DataFrame(columns=['dates', 'distrito', 'concelho'])
                    table_row['dates'] = dates
                    table_row['distrito'] = distrito
                    table_row['concelho'] = concelhos[concelho_id]

                    result = pd.concat([result, table_row])

                driver.find_element_by_xpath('//*[@id="divHorario"]/button[1]').click()
            except:
                print ("Error")
                button = WebDriverWait(driver, 5).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="myModal_1"]/div/div/div[3]/button'))).click()

    driver.close()
    result = result.sort_values('dates')

    return result


import pickle
import argparse
import numpy as np
from keras.layers import Conv2D, Dense, Flatten, MaxPool2D, Dropout
from keras.layers import BatchNormalization, Activation, LeakyReLU
from keras.models import Model, Input, load_model
from keras.utils import to_categorical
from keras.callbacks import EarlyStopping, ModelCheckpoint

MAX_LEN = 200

def build():
    input_shape = Input([20, MAX_LEN, 1])

    out = Conv2D(32, [4, 10], padding='same')(input_shape)
    out = BatchNormalization()(out)
    out = LeakyReLU()(out)
    # out = MaxPool2D([2, 2])(out)
    # out = Dropout(0.4)(out)

    out = Conv2D(32, [4, 10], strides=[1, 2], padding='same')(out)
    out = BatchNormalization()(out)
    out = LeakyReLU()(out)
    out = MaxPool2D([2, 2])(out)
    out = Dropout(0.4)(out)

    out = Conv2D(64, [4, 10], strides=[1, 2], padding='same')(out)
    out = BatchNormalization()(out)
    out = LeakyReLU()(out)
    # out = MaxPool2D([2, 2])(out)
    # out = Dropout(0.4)(out)

    out = Conv2D(64, [4, 10], strides=[1, 2], padding='same')(out)
    out = BatchNormalization()(out)
    out = LeakyReLU()(out)
    out = MaxPool2D([2, 2])(out)
    out = Dropout(0.4)(out)

    out = Flatten()(out)

    out = Dense(64)(out)
    out = BatchNormalization()(out)
    out = Activation('relu')(out)
    out = Dropout(0.4)(out)
    #
    # out = Dense(32)(out)
    # out = BatchNormalization()(out)
    # out = Activation('relu')(out)
    # out = Dropout(0.7)(out)

    out = Dense(41)(out)
    out = Activation('softmax')(out)

    model = Model(inputs=input_shape, outputs=out)
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])

    return model

def datagen(x, y, batch_size):
    num = len(y)
    while True:
        xx = np.zeros([batch_size, 20, MAX_LEN, 1])
        ind = np.random.choice(num, batch_size, replace=False)
        for i, j, in enumerate(ind):
            # max_ind = np.argmax(x[j].sum(0))
            # left = max(0, max_ind - MAX_LEN//2)
            # piece = x[j][:, left:left+MAX_LEN].reshape([20, -1, 1])
            # xx[i, :, :piece.shape[1]] = piece
            xx[i, :, :x[j].shape[1]] = x[j][:, :MAX_LEN].reshape([20, -1, 1])
        yield xx, y[ind]

def score(y, preds):
    sc = np.zeros(41, dtype=np.float64)
    sc[:3] = np.array([1, 1/2, 1/3])
    count = 0
    for i in range(len(y)):
        ans = y[i]
        pred = preds[i]
        pred = np.argsort(pred)[::-1]
        count += np.sum((pred == ans) * sc)
    return count

def run(args):
    with open(args.xy, 'rb') as f:
        pk = pickle.load(f)
    data, labels = pk['data'], pk['labels']
    labels = to_categorical(labels, 41)

    idx = np.random.choice(len(data), len(data), replace=False)
    data = data[idx]
    labels = labels[idx]

    x_train = data[:args.train_num]
    x_valid = data[args.train_num:]
    y_train = labels[:args.train_num]
    y_valid = labels[args.train_num:]

    if args.semi:
        with open(args.semi, 'rb') as f:
            pk = pickle.load(f)
        s_data = pk['data']
        s_labels = to_categorical(pk['labels'], 41)
        idx = np.random.choice(len(s_data), 1000)
        s_data = s_data[idx]
        s_labels = s_labels[idx]
        x_train = np.concatenate([x_train, s_data])
        y_train = np.concatenate([y_train, s_labels])

    callbacks = [EarlyStopping(monitor='val_loss', patience=5),
                 ModelCheckpoint(args.model_path, monitor='val_loss', save_best_only=True)]

    model = build()
    # model.summary()
    model.fit_generator(
        datagen(x_train, y_train, args.batch_size),
        epochs=args.epochs,
        steps_per_epoch=100,
        validation_data=datagen(x_valid, y_valid, args.batch_size),
        validation_steps=10,
        callbacks=callbacks
    )
    # model.save(args.model_path)

def parse():
    parser = argparse.ArgumentParser()
    parser.add_argument('xy')
    parser.add_argument('model_path')
    parser.add_argument('-i', type=int, default=100, dest='epochs')
    parser.add_argument('-b', type=int, default=200, dest='batch_size')
    parser.add_argument('-n', type=int, default=8000, dest='train_num')
    parser.add_argument('-s', dest='semi')
    return parser.parse_args()

if __name__ == '__main__':
    run(parse())
    # f = lambda: None
    # for i in range(31, 40):
    #     setattr(f, 'xy', 'pickle/xy.pickle')
    #     setattr(f, 'model_path', 'mfcc/mfcc%d.mdn' % i)
    #     setattr(f, 'batch_size', 200)
    #     setattr(f, 'train_num', 8500)
    #     setattr(f, 'epochs', 100)
    #     setattr(f, 'semi', None)
    #     run(f)


# USAGE
# python scripts/crop-to-object.py -i images/output/uss-freedom-original.jpg

# import necessary packages
import argparse
import cv2

# construct the argument parser
ap = argparse.ArgumentParser()
ap.add_argument("-i","--image", type=str,
                help="path to input image")
args = vars(ap.parse_args())

# load, crop, save and show
image = cv2.imread(args["image"])
cropped = image[700:1050, 300:1400]
(h, w, c) = image.shape[:3]
print("width: {} pixels".format(w))
print("height: {} pixels".format(h))
print("channels: {}".format(c))
cv2.imshow("Cropped", cropped)
cv2.imwrite("images/output/uss-freedom-cropped.jpg", cropped)
cv2.waitKey(0)


from collections import Counter
mn = input()
m_n = mn.split(' ')
m = int(m_n[0])
n = int(m_n[1])
input_array = input()
input_array_list = input_array.split(' ')
input_array_set = set(input_array_list)

like_set = input()
input_like_set = set(like_set.split(' '))

dislike_set = input()
input_dislike_set = set(dislike_set.split(' '))

result = 0
like_inter = input_array_set.intersection(input_like_set)
dislike_inter = input_array_set.intersection(input_dislike_set)

c=Counter(input_array_list)
for item in like_inter:
    result += c[str(item)]

for item in dislike_inter:
    result -= c[str(item)]

print(result)


import io
import json
from dataclasses import dataclass

import avro
from avro.io import DatumWriter, DatumReader, BinaryDecoder

from kpong import PingPongMessage
from kpong.schema import PING_PONG_SCHEMA

def ping_pong_deserializer(message):
    return deserializer(message, PING_PONG_SCHEMA, PingPongMessage.from_dict)

def deserializer(datum, schema: str, mapper: callable):
    avro_schema = avro.schema.parse(json.dumps(schema))
    reader = DatumReader(avro_schema)
    message_bytes = io.BytesIO(datum)
    decoder = BinaryDecoder(message_bytes)
    msg = reader.read(decoder)

    return mapper(msg)

def serializer(message: dataclass, schema):
    avro_schema = avro.schema.parse(json.dumps(schema))

    writer = DatumWriter(avro_schema)
    bytes_writer = io.BytesIO()
    encoder = avro.io.BinaryEncoder(bytes_writer)
    writer.write(message.__dict__, encoder)
    bs = bytes_writer.getvalue()

    return bs


from __future__ import annotations

import logging

import click
import numpy as np

import vpype as vp

from .cli import cli
from .decorators import global_processor

try:
    # noinspection PyUnresolvedReferences
    import vpype_viewer

    _vpype_viewer_ok = True
except ImportError:  # pragma: no cover
    _vpype_viewer_ok = False

__all__ = ("show",)

COLORS = [
    (0, 0, 1),
    (0, 0.5, 0),
    (1, 0, 0),
    (0, 0.75, 0.75),
    (0, 1, 0),
    (0.75, 0, 0.75),
    (0.75, 0.75, 0),
    (0, 0, 0),
]

@cli.command(group="Output")
@click.option("--classic", is_flag=True, help="Use the classic viewer.")
@click.option("--force", is_flag=True, hidden=True, help="Force modern viewer")
@click.option("-p", "--show-pen-up", is_flag=True, help="Display pen-up trajectories.")
@click.option("-d", "--show-points", is_flag=True, help="Display paths points with dots.")
@click.option("-o", "--outline", is_flag=True, help="Display in outline mode (modern only).")
@click.option(
    "-c",
    "--colorful",
    is_flag=True,
    help="Display in outline colorful mode (takes precedence over --outline).",
)
@click.option("-a", "--show-axes", is_flag=True, help="Display axes (classic only).")
@click.option(
    "-g", "--show-grid", is_flag=True, help="Display grid (implies -a, classic only)."
)
@click.option(
    "-h", "--hide-legend", is_flag=True, help="Do not display the legend (classic only)."
)
@click.option(
    "-u",
    "--unit",
    type=str,
    default="px",
    help="Units of the plot (when --show-grid is active, classic only).",
)
@global_processor
def show(
    document: vp.Document,
    classic: bool,
    force: bool,
    show_pen_up: bool,
    show_points: bool,
    outline: bool,
    colorful: bool,
    show_axes: bool,
    show_grid: bool,
    hide_legend: bool,
    unit: str,
):
    """Display the geometry in an graphical user interface.

    By default, this command use a modern, hardware-accelerated viewer (currently in beta) with
    a preview mode (adjustable pen width and opacity) and interactive controls to adjust
    display options. This viewer requires OpenGL 3.3 support.

    The original, Matplotlib-based viewer is still available with the `--classic` option. The
    classic viewer does not have interactive controls for display options. Use the command-line
    options to customize the display.
    """

    if not classic:
        # test for vpype_viewer
        if not _vpype_viewer_ok:
            logging.warning(
                "!!! show: vpype viewer not available, reverting to classic mode. Note: use "
                "`pip install vpype[all]` to install the vpype viewer."
            )
            classic = True
        else:
            mgl_ok = _test_mgl()
            if not mgl_ok and not force:
                classic = True
                logging.warning("!!! show: ModernGL not available, reverting to classic mode.")
            elif not mgl_ok and force:
                logging.warning("!!! show: ModernGL not available but forced to vpype viewer.")

    if classic:
        _show_mpl(
            document,
            show_axes,
            show_grid,
            show_pen_up,
            show_points,
            hide_legend,
            colorful,
            unit,
        )
    else:
        view_mode = vpype_viewer.ViewMode.PREVIEW
        if outline or show_points:
            view_mode = vpype_viewer.ViewMode.OUTLINE
        if colorful:
            view_mode = vpype_viewer.ViewMode.OUTLINE_COLORFUL

        vpype_viewer.show(
            document, view_mode=view_mode, show_pen_up=show_pen_up, show_points=show_points
        )

    return document

def _test_mgl() -> bool:
    """Tests availability of ModernGL."""
    # noinspection PyBroadException
    try:
        import glcontext

        backend = glcontext.default_backend()
        ctx = backend(mode="standalone", glversion=330)
        if ctx.load("glProgramUniform1iv") == 0:
            logging.info("ModernGL detection: glProgramUniform1iv not found")
            return False
    except Exception as exc:
        logging.info(f"ModernGL detection failed with error {exc}")
        return False

    return True

def _show_mpl(
    document: vp.Document,
    show_axes: bool,
    show_grid: bool,
    show_pen_up: bool,
    show_points: bool,
    hide_legend: bool,
    colorful: bool,
    unit: str,
):
    """Display the geometry using matplotlib.

    By default, only the geometries are displayed without the axis. All geometries are
    displayed with black. When using the `--colorful` flag, each segment will have a different
    color (default matplotlib behaviour). This can be useful for debugging purposes.
    """

    # deferred import to optimise startup time
    try:
        import matplotlib.collections
        import matplotlib.pyplot as plt
    except ImportError:
        logging.warning(
            "!!! show: classic viewer not available, ignore command. Note: use `pip install "
            "matplotlib` to enable the classic viewer."
        )
        return

    scale = 1 / vp.convert_length(unit)

    fig = plt.figure()
    color_idx = 0
    collections = {}

    # draw page boundaries
    if document.page_size:
        w = document.page_size[0] * scale
        h = document.page_size[1] * scale
        dw = 10 * scale
        plt.plot(
            np.array([0, 1, 1, 0, 0]) * w,
            np.array([0, 0, 1, 1, 0]) * h,
            "-k",
            lw=0.25,
            label=None,
        )
        plt.fill(
            np.array([w, w + dw, w + dw, dw, dw, w]),
            np.array([dw, dw, h + dw, h + dw, h, h]),
            "k",
            alpha=0.3,
            label=None,
        )

    for layer_id, lc in document.layers.items():
        if colorful:
            color = COLORS[color_idx:] + COLORS[:color_idx]
            marker_color = "k"
            color_idx += len(lc)
        else:
            color = COLORS[color_idx]  # type: ignore
            marker_color = [color]  # type: ignore
            color_idx += 1
        if color_idx >= len(COLORS):
            color_idx = color_idx % len(COLORS)

        layer_lines = matplotlib.collections.LineCollection(
            (vp.as_vector(line) * scale for line in lc),
            color=color,
            lw=1,
            alpha=0.5,
            label=str(layer_id),
        )
        collections[layer_id] = [layer_lines]
        plt.gca().add_collection(layer_lines)

        if show_points:
            points = np.hstack([line for line in lc]) * scale
            layer_points = plt.gca().scatter(
                points.real, points.imag, marker=".", c=marker_color, s=16
            )
            collections[layer_id].append(layer_points)

        if show_pen_up:
            pen_up_lines = matplotlib.collections.LineCollection(
                (
                    (vp.as_vector(lc[i])[-1] * scale, vp.as_vector(lc[i + 1])[0] * scale)
                    for i in range(len(lc) - 1)
                ),
                color=(0, 0, 0),
                lw=0.5,
                alpha=0.5,
            )
            collections[layer_id].append(pen_up_lines)
            plt.gca().add_collection(pen_up_lines)

    plt.gca().invert_yaxis()
    plt.axis("equal")
    plt.margins(0, 0)

    if not hide_legend:
        lgd = plt.legend(loc="upper right")
        # we will set up a dict mapping legend line to orig line, and enable
        # picking on the legend line
        line_dict = {}
        for lgd_line, lgd_text in zip(lgd.get_lines(), lgd.get_texts()):
            lgd_line.set_picker(True)  # 5 pts tolerance
            lgd_line.set_pickradius(5)
            layer_id = int(lgd_text.get_text())
            if layer_id in collections:
                line_dict[lgd_line] = collections[layer_id]

        def on_pick(event):
            line = event.artist
            vis = not line_dict[line][0].get_visible()
            for ln in line_dict[line]:
                ln.set_visible(vis)

            if vis:
                line.set_alpha(1.0)
            else:
                line.set_alpha(0.2)
            fig.canvas.draw()

        fig.canvas.mpl_connect("pick_event", on_pick)

    if show_axes or show_grid:
        plt.axis("on")
        plt.xlabel(f"[{unit}]")
        plt.ylabel(f"[{unit}]")
    else:
        plt.axis("off")
    if show_grid:
        plt.grid("on")
    plt.show()


#Oppgave3
def billett():
    alder = int(input("Skriv inn alder på kjøperen."))
    billettpris = 0

    if alder <= 17:
        billettpris = 30
    elif alder > 17 and alder < 63:
        billettpris = 50
    elif alder >= 63:
        billettpris = 35

    print("Billetten din koster", billettpris, "kroner.")

billett()

# Jeg satt opp en prosedyre med to ulike variabler. Hentet inn alder fra bruker
# og satt opp en if liste som definerte prisen ut ifra alderen.


import config
import pygame
import math

class static_shape_object:
    def __init__(self, position, vertices) -> None:
        ''' vertices are relative to given position'''
        self.vertices = vertices
        self.position = position
        self.colliding = False
        self.color = config.DEFAULT_SHAPE_COLOR
        self.world_vertices = list(map(lambda x: (x[0] + self.position[0], x[1] + self.position[1]), self.vertices))
        self.centralize_polygon_position()

    def draw(self, surface):
        pygame.draw.polygon(surface, self.color, self.world_vertices, config.POLYGON_BORDER_WIDTH)
        pygame.draw.circle(surface, (255,0,0), self.position, 2)
        fill_polygon_with_alpha(surface, self.world_vertices, self.color)

    def centralize_polygon_position(self):
        self.position = get_centroid(self.world_vertices)
        self.vertices = []
        for vertex in self.world_vertices:
            self.vertices.append(calc_vector(self.position, vertex))

class dynamic_shape_object(static_shape_object):
    def __init__(self, position, vertices) -> None:
        super().__init__(position, vertices)
        self.facing = [0, 1]
        self.moved = False

    def udpdate_world_verices(self):
        self.world_vertices = list(map(lambda x: (x[0] + self.position[0], x[1] + self.position[1]), self.vertices))

    def rotate(self, angle):
        ''' rotates vertices cunter-clockwise by given angle in radians'''
        cos = math.cos(angle)
        sin = math.sin(angle)
        for vertex in self.vertices:
            x, y = vertex
            vertex[0] = x * cos - y * sin
            vertex[1] = x * sin + y * cos

        x, y = self.facing
        self.facing[0] = x * cos - y * sin
        self.facing[1] = x * sin + y * cos
        self.moved = True

    def move_forwards(self):
        self.position[0] += self.facing[0] * config.MOVEMENT_MULTIPLIER
        self.position[1] += self.facing[1] * config.MOVEMENT_MULTIPLIER
        self.moved = True

    def move_backwards(self):
        self.position[0] -= self.facing[0] * config.MOVEMENT_MULTIPLIER
        self.position[1] -= self.facing[1] * config.MOVEMENT_MULTIPLIER
        self.moved = True

    def update_variables(self, world_shapes):
        if self.moved:
            self.handle_collisions(world_shapes)
            self.udpdate_world_verices()
            self.moved = False

    def handle_collisions(self, world_shapes):
        self_edges = generate_edge_data(self)
        moved = False
        for shape in world_shapes:
            if shape is not self:
                shape_edges = generate_edge_data(shape)
                for diag in self.vertices:
                    for point, dir in shape_edges:
                        vector = line_intersection(self.position, diag, point, dir)
                        if vector != None:
                            self.position[0] -= (diag[0] - vector[0])
                            self.position[1] -= (diag[1] - vector[1])
                            moved = True

                if moved:
                    self_edges = generate_edge_data(self)

                for diag in shape.vertices:
                    for point, dir in self_edges:
                        vector = line_intersection(shape.position, diag, point, dir)
                        if vector != None:
                            self.position[0] += (diag[0] - vector[0])
                            self.position[1] += (diag[1] - vector[1])
                            self_edges = generate_edge_data(self)
                            moved = True
        if moved:
            self.udpdate_world_verices()

def get_centroid(vertices):
    x = y = 0
    area = 0
    n = len(vertices)
    for i in range(n):
        p1 = vertices[i]
        p2 = vertices[(i + 1) % n]
        tmp = p1[0] * p2[1] - p2[0] * p1[1]
        area += tmp
        x += (p1[0] + p2[0]) * tmp
        y += (p1[1] + p2[1]) * tmp

    return [x / (3*area), y / (3*area)]

def generate_edge_data(shape):
    edge_data = []
    vertices = shape.vertices
    n = len(vertices)
    for i in range(n):
        vector = calc_vector(vertices[i], vertices[(i + 1) % n])
        position = (vertices[i][0] + shape.position[0], vertices[i][1] + shape.position[1])
        edge_data.append((position, vector))
    return edge_data

def line_intersection(p, r, q, s):
    ''' <p,q> - points,  <r,s> - vectors, if lines do intersect with each other return vetor from p to intersection point'''
    a = cross_product_2d(r, s)
    vec = calc_vector(p, q)
    b = cross_product_2d(vec, s)
    if a == 0:
        if b == 0:
            v1 = calc_vector(p, q)
            v2 = calc_vector(p, add_vectors(q, s))
            r_length = get_vector_length(r)
            if r_length != 0:
                r_versor = calc_versor(r, r_length)
                d_p = min(dot_product(r_versor, v1), dot_product(r_versor, v2))
                if 0 < d_p < r_length:
                    return multiply_vector_by_scalar(d_p, r)
    else:
        t = b / a
        s = cross_product_2d(vec, r) / a
        if 0 < t < 1 and 0 < s < 1:
            return multiply_vector_by_scalar(t, r)
    return None

def fill_polygon_with_alpha(surface, polygon, color):
    x_range = [math.inf, -math.inf]
    y_range = [math.inf, -math.inf]
    for vertex in polygon:
        x_range[0] = min(x_range[0], vertex[0])
        x_range[1] = max(x_range[1], vertex[0])
        y_range[0] = min(y_range[0], vertex[1])
        y_range[1] = max(y_range[1], vertex[1])

    surface_rect = (x_range[0], y_range[0], x_range[1] - x_range[0], y_range[1] - y_range[0])
    relative_vertices = list(map(lambda x: (x[0] - surface_rect[0], x[1] - surface_rect[1]), polygon))
    polygon_surface = pygame.Surface(surface_rect[2:])
    polygon_surface.set_colorkey((0, 0, 0))
    polygon_surface.set_alpha(config.POLYGON_FILL_ALPHA)
    pygame.draw.polygon(polygon_surface, color, relative_vertices)
    surface.blit(polygon_surface, surface_rect[:2])

def calc_vector(p1, p2):
    return [p2[0] - p1[0], p2[1] - p1[1]]

def get_vector_length(v):
    return math.sqrt(v[0]**2 + v[1]**2)

def calc_versor(v, length):
    length = math.sqrt(v[0]**2 + v[1]**2)
    return (v[0] / length , v[1] / length)

def add_vectors(v1, v2):
    return (v1[0] + v2[0], v1[1] + v2[1])

def subtract_vectors(v1, v2):
    return (v1[0] - v2[0], v1[1] - v2[1])

def multiply_vector_by_scalar(s, v):
    return (s * v[0], s * v[1])

def cross_product_2d(v1, v2):
    return v1[0]* v2[1] - v1[1]* v2[0]

def dot_product(v0, v1):
    return v0[0] * v1[0] + v0[1] * v1[1]


from flask import Blueprint, render_template, request, jsonify, session
import random, json

views = Blueprint(__name__, "views")

the_score = 0

board_data = []
hand_data = []

vowels = ['a', 'e', 'i', 'o', 'u']

 # Define the letters with their corresponding values
letter_values = {
    'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 'h': 4,
    'i': 1, 'j': 8, 'k': 5, 'l': 1, 'm': 3, 'n': 1, 'o': 1, 'p': 3,
    'q': 10, 'r': 1, 's': 1, 't': 1, 'u': 1, 'v': 4, 'w': 4, 'x': 8,
    'y': 4, 'z': 10
}

# Define the weights of the high-value letters
# The weights determine how often the letter will appear
letter_weights = {
    'j': 0.1, 'q': 0.1, 'x': 0.2, 'z': 0.2
}

def generate_letters():
    letters = []
    vowel_count = 0

    for i in range(7):
        if i < 2 or vowel_count < 2:
            # Generate a random letter
            letter = chr(random.randint(ord('a'), ord('z')))

            # Check if it's a vowel
            if letter in vowels:
                vowel_count += 1
        else:
            # Generate a random consonant
            # Use letter_weights to determine the probability of selecting a high-value letter
            if random.random() < sum(letter_weights.values()):
                letter = random.choices(list(letter_weights.keys()), weights=list(letter_weights.values()))[0]
            else:
                letter = chr(random.randint(ord('b'), ord('y')))

        letters.append(letter)

    # Shuffle the letters to make the distribution more random
    random.shuffle(letters)

    return letters

def refresh_letters(word, hand):
    # Iterate through each active letter, replace them with a new letter
    for letter in word.lower():
        newletter = chr(random.randint(ord('a'), ord('z')))
        hand = hand.replace(letter, newletter, 1)
    return hand

def validate_word(word):
    # Load dictionary file
    # Credit: https://github.com/dwyl/english-words for dictionary
    with open('assets/words_alpha.txt', 'r') as f:
        dictionary = set([word.strip() for word in f.readlines()])

    # Check if string is in dictionary, then reformat and return it
    if word.lower() in dictionary:
        return True
    else:
        return '"%s" is not a valid word.' % word.lower().capitalize()

def register_slots(slots, word):
    #returns an array that maps active letters to their slots to fill board
    return []

def calculate_score(word):
    score = 0
    for letter in word.lower():
        if letter in letter_values:
            score += letter_values[letter]
    return score

@views.route("/")
def home():
    letters = generate_letters()

    return render_template('index.html', letters=letters, score=the_score, name="Scrabble!")

@views.route("/populate_board", methods=["POST"])
def populate_board():
    print("populate_board")

@views.route("/populate_hand", methods=["POST"])
def populate_hand():
    print("populate_hand")

@views.route("/submit-word", methods=["POST"])
def play_word():
    # handle the request data
    word = request.json.get("word")
    slots = request.json.get("slots")
    oldletters = request.json.get("old_letters")

    #regenerate more letters for empty slots
    letters = refresh_letters(word, oldletters)

    # validate the word given to the server
    result = validate_word(word)

    # calculate the total value of the word
    score = calculate_score(word)

    # return a JSON response
    return jsonify(message=result, score=score, letters=letters)


from glob import glob
import time
import os.path
import os
import numpy as np
from .utils import return_diff_structures, create_output_file

def check_structure(user: str,
                    session: str,
                    movement: str,
                    warping_paths: np.ndarray,
                    output_path: str,
                    plot_path: str,
                    segment_divider: int = 25,
                    diff_max: int = 3,
                    diff_min: int = 0.13,
                    area_diff: int = 10,
                    output: bool = True,
                    excel: bool = True,
                    csv: bool = True,
                    debug: bool = True,
                    plotting: bool = False,
                    rewrite: bool = False):
    """
    Check the structure of audio recordings based on the slope of warping paths.

    Args:
        user:
        session:
        movement:
        warping_paths:
        output_path:
        plot_path:
        segment_divider:
        diff_max:
        diff_min:
        area_diff:
        output:
        excel:
        csv:
        debug:
        plotting:
        rewrite:
    """

    output_diff_filename = f'{user}_{session}_mov{movement}_diff_structure'
    output_same_filename = f'{user}_{session}_mov{movement}_same_structure'

    if not rewrite:
        if os.path.exists(f'{output_path}/xlsx/{output_same_filename}.xlsx'):
            return None

    # starts the time counter
    if debug:
        tcalcstart = time.time()

    # returns list of filenames with different structures and list of different areas from DTW
    diff_structure_list, same_structure_list = return_diff_structures(warping_paths=warping_paths,
                                                                      output_path=output_path,
                                                                      plot_path=plot_path,
                                                                      segment_divider=segment_divider,
                                                                      diff_max=diff_max,
                                                                      diff_min=diff_min,
                                                                      area_diff=area_diff,
                                                                      plotting=plotting,
                                                                      debug=debug)

    if not os.path.isdir(output_path):
        os.mkdir(output_path)

    if output:
        create_output_file(diff_structure_list=diff_structure_list, path_to_output=output_path,
                           output_filename=output_diff_filename,
                           excel=excel, csv=csv)
        create_output_file(diff_structure_list=same_structure_list, path_to_output=output_path,
                           output_filename=output_same_filename,
                           excel=excel, csv=csv)

    # stops the timer and writes output to console
    if debug:
        tcalcend = time.time()
        calctime = round(tcalcend - tcalcstart, 2)

    num_of_diff_structure = len(diff_structure_list)

    print("Calculation finished!")
    if debug:
        print(f"Total calculation time: {calctime}")
    print(f"Number of different structures found: {num_of_diff_structure}")
    print(f'List of recordings with different structures: {diff_structure_list}\n')

if __name__ == '__main__':

    from ..src.config import *

    chroma_style = 'chroma'  # chroma or beat

    for no_of_comp, user in enumerate(users):
        for session, reference_name in zip(sessions[no_of_comp], references[no_of_comp]):
            for movement in movements:

                ref_file = f'{reference_name}_{movement}'
                plot_path = f'{user}/{session}/mov{movement}'
                reference_CD = reference_name[:3]
                print(f'reference_CD: {reference_CD}, {user}, {session}, mov{movement}')

                warping_paths = glob(f'../data/{user}/{session}/mov{movement}/warping_paths/{chroma_style}/*')

                check_structure(user=user,
                                session=session,
                                movement=movement,
                                warping_paths=warping_paths,
                                plot_path=plot_path,
                                output_path=f'outputs',
                                plotting=True,
                                debug=False,
                                excel=True,
                                csv=True,
                                output=True,
                                rewrite=True)
                print('---segment done---')

    print('---done---')


from __future__ import print_function, division
import time
import torch
import numpy as np
import torch.nn.functional as F
from torch.autograd import Variable
from torchnet.meter import ConfusionMeter

use_cuda = torch.cuda.is_available()

# Compute log sum exp in a numerically stable way for the forward algorithm
def log_sum_exp(vec):
    """ Given a vector, return log_sum_exp with last dimension reduced.
    """
    last_dimension = len(vec.size()) - 1
    max_score, _ = torch.max(vec, last_dimension)
    if last_dimension > 0:
        _exp = torch.exp(vec - max_score.unsqueeze(last_dimension))
        _sum = torch.sum(_exp, last_dimension)
    else:
        _exp = torch.exp(vec - max_score)
        _sum = torch.sum(_exp)
    _log = max_score + torch.log(_sum)
    return _log

def cuda_var_wrapper(var, volatile=False):
    var = Variable(var, volatile=volatile)
    if use_cuda:
        var = var.cuda()
    return var

def cuda_tensor_wrapper(tensor):
    if use_cuda:
        tensor = tensor.cuda()
    return tensor

def timeit(method):
    def timed(*args, **kw):
        ts = time.time()
        result = method(*args, **kw)
        te = time.time()
        print('%r  %2.2f ms' % (method.__name__, (te - ts) * 1000))
        return result
    return timed

def parameter_summary(writer, name, param, global_step):
    if isinstance(param, Variable):
        param = param.data
    writer.add_scalars('Train/' + name,
        {name + '_mean': torch.mean(param),
        name + '_std': torch.std(param),
        name + '_max': torch.max(param),
        name + '_min': torch.min(param)}, global_step)
    writer.add_histogram(name, param.clone().cpu().numpy(), global_step, bins='doane')

def sequence_mask(sequence_length, max_len=None):
    if isinstance(sequence_length, Variable):
        sequence_length = sequence_length.data
    if max_len is None:
        max_len = sequence_length.max()
    batch_size = sequence_length.size(0)
    seq_range = torch.arange(0, max_len).long()
    seq_range_expand = seq_range.unsqueeze(0).expand(batch_size, max_len)
    if sequence_length.is_cuda:
        seq_range_expand = seq_range_expand.cuda()
    seq_length_expand = (sequence_length.unsqueeze(1).expand_as(seq_range_expand))
    return (seq_range_expand < seq_length_expand).float()

def precision_recall_f1(confusion_matrix, average=True):
    """Given confusion_matrix in numpy, calculate precision, recall and f1 score.
    """
    confusion_matrix = confusion_matrix.value()
    dim = confusion_matrix.shape[0]
    TP_FP = np.sum(confusion_matrix, 0)
    TP_FN = np.sum(confusion_matrix, 1)
    precision, recall, f1_score = np.zeros(dim), np.zeros(dim), np.zeros(dim)

    for i in range(dim):
        if confusion_matrix[i, i] == 0:
            precision[i] = 0
            recall[i] = 0
            f1_score[i] = 0
        else:
            precision[i] = (confusion_matrix[i, i] / TP_FP[i])
            recall[i] = (confusion_matrix[i, i] / TP_FN[i])
            f1_score[i] = 2 * precision[i] * recall[i] / (precision[i] + recall[i])
    if average:
        return np.mean(precision), np.mean(recall), np.mean(f1_score)
    else:
        return precision, recall, f1_score

def get_batch_accuracy(labels, output, lengths):
    correct = 0.0
    total = 0.0
    if len(output.size()) > 2:
        _, output = torch.max(F.softmax(output, 2), 2)
    if isinstance(output, Variable):
        output = output.data
    correct_matrix = torch.eq(output, labels.data).float()
    mask = sequence_mask(lengths)
    correct = torch.sum(correct_matrix * mask)
    total = torch.sum(lengths.data)
    return correct, total

def evaluate(model, dataloader, crf, criterion, f1=False):
    model.eval()
    if f1:
        confusion_matrix = ConfusionMeter(8)
        confusion_matrix.reset()
    correct, total = 0, 0
    loss_total = 0
    for i, (features, labels, _, lengths) in enumerate(dataloader):
        max_length = max(lengths)
        features = cuda_var_wrapper(features[:, :, :max_length], volatile=True)
        labels = cuda_var_wrapper(labels[:, :max_length], volatile=True)
        lengths = cuda_var_wrapper(lengths)
        if crf:
            _, output = model(features, lengths)
            loss = model.forward_alg(features, labels, lengths)
            preds = output
        else:
            output = model(features)
            loss = criterion(output.contiguous().view(-1, 8), labels.contiguous().view(-1))
            _, preds = torch.max(F.softmax(output, 2), 2)
        correct_batch, total_batch = get_batch_accuracy(labels, output, lengths)
        loss_total += loss.data[0] * features.size()[0]
        correct += correct_batch
        total += total_batch
        if f1:
            if isinstance(preds, Variable):
                preds = preds.data
            for pred, truth, length in zip(preds, labels.data, lengths.data):
                confusion_matrix.add(pred[:length], truth[:length])
    if f1:
        # print(confusion_matrix.value())
        precision, recall, f1 = precision_recall_f1(confusion_matrix)
        return correct / total, loss_total, precision, recall, f1
    return correct / total, loss_total

def eval(model, features, labels, lengths, crf, criterion):
    model.eval()
    if crf:
        _, output = model(features, lengths)
        loss = model.forward_alg(features, labels, lengths)
    else:
        output = model(features)
        loss = criterion(output.contiguous().view(-1, 8), labels.contiguous().view(-1))
    loss_batch = loss.data[0] * features.size()[0]
    correct_batch, total_batch = get_batch_accuracy(labels, output, lengths)
    return correct_batch, total_batch, loss_batch

def crf_param(model):
    """Given the model with CRF as the last layer, return the crf transition
    parameters without the START and STOP column and row.
    """
    crf_param = list(model.children())[-1].transitions.cpu().data.numpy()
    crf_param_2 = np.delete(crf_param, 8, 0)
    crf_param_2 = np.delete(crf_param_2, 9, 1)
    return torch.from_numpy(crf_param_2)


"""

function that takes two nums as input and find the big of two nums
"""

#WRITE THE FUNCTION
def bigger(n1,n2):
    if(n1>n2):
        return n1
    else:
        return  n2

#call the function
num1=10
num2=30

v1 = bigger(num1,num2)
print("bigger of {} and {} is {}".format(num1,num2,v1))

num1=80
num2=20

v2 = bigger(num1,num2)
print("bigger of {} and {} is {}".format(num1,num2,v2))


# completed DM-trajectory code with scattering added (in progress)

import numpy as np
import uproot_methods as urm
import matplotlib.pyplot as plt

# -------------------------DETECTOR GEOMETRY--------------------------------
# based on dimensions of DUNE detector -- sourced from TDR doc
# using scale of 12 x 14 x 58.2m centered around the origin
x_scale = 12
y_scale = 14
z_scale = 58.2

# calculate the points of each face based on scale
x_max = x_scale / 2
x_min = -x_scale / 2
y_max = y_scale / 2
y_min = -y_scale / 2
z_max = z_scale / 2
z_min = -z_scale / 2

# r_max
# must be large enough s.t. no matter disk orientation target is covered
r_max = np.sqrt((x_scale ** 2) + (y_scale ** 2) + (z_scale ** 2))/2

# ---------------------SAMPLE TRAJECTORIES-----------------------------------
# store found entry and exit points
entries = []
exits = []

# store c and phis to check distribution
cs = []
phis = []

# store velocity magnitudes to check distribution
speeds = []

# iterate for some number of samples of trajectories
for j in range(100):
    # ------------------------DM DISK ORIENTATION------------------------
    # sample c uniformly from -1 to 1
    c = 2.0 * np.random.random() - 1.0
    cs.append(c)
    # convert c to theta(azimuthal angle)
    theta = np.arccos(c)

    # sample phi(polar angle) uniformly from 0 to 2pi
    phi = 2.0 * np.pi * np.random.random()
    phis.append(phi)

    # sample alpha(angle about disk) uniformly from 0 to 2pi
    alpha = 2.0 * np.pi * np.random.random()

    # sample probability of radius uniformly from 0 to 1
    prob_r = np.random.random()
    # calculate radius from probability
    r = r_max * np.sqrt(prob_r)

    # ----------------------TRAJECTORY CALCULATION--------------------------
    # initial disk orientation, fixed to z axis
    disk = urm.TVector3(np.cos(alpha), np.sin(alpha), 0)
    # disk oriented by theta around y-axis then by phi around z-axis
    disk = disk.rotatey(theta)
    disk = disk.rotatez(phi)
    # resize disk to radius
    disk = r * disk

    # trajectory: <x, y, z> = lambda * [orientation] + [disk]
    orient = [np.sqrt(1 - c ** 2) * np.cos(phi), np.sqrt(1 - c ** 2) * np.sin(phi), c]

    # ---------------------ENTRY AND EXIT POINTS---------------------------
    # to store solved trajectories at each plane
    faces = []
    lambdas = np.zeros(6)
    # to store trajectories that are either entry or exit points
    valid_points = []
    valid_lambdas = []

    # for each of the 6 faces: solve lamda using fixed axis point then subsequently solve trajectory equation
    # face 0 -> xy plane at z_max
    lambdas[0] = (z_max - disk.z) / orient[2]
    faces.append(urm.TVector3(lambdas[0] * orient[0] + disk.x, lambdas[0] * orient[1] + disk.y, z_max))

    # face 1 -> xy plane at z_min
    lambdas[1] = (z_min - disk.z) / orient[2]
    faces.append(urm.TVector3(lambdas[1] * orient[0] + disk.x, lambdas[1] * orient[1] + disk.y, z_min))

    # face 2 -> zy plane at x_max
    lambdas[2] = (x_max - disk.x) / orient[0]
    faces.append(urm.TVector3(x_max, lambdas[2] * orient[1] + disk.y, lambdas[2] * orient[2] + disk.z))

    # face 3 -> zy plane at x_min
    lambdas[3] = (x_min - disk.x) / orient[0]
    faces.append(urm.TVector3(x_min, lambdas[3] * orient[1] + disk.y, lambdas[3] * orient[2] + disk.z))

    # face 4 -> xz plane at y_max
    lambdas[4] = (y_max - disk.y) / orient[1]
    faces.append(urm.TVector3(lambdas[4] * orient[0] + disk.x, y_max, lambdas[4] * orient[2] + disk.z))

    # face 5 -> xz plane at y_min
    lambdas[5] = (y_min - disk.y) / orient[1]
    faces.append(urm.TVector3(lambdas[5] * orient[0] + disk.x, y_min, lambdas[5] * orient[2] + disk.z))

    # check which (if any) points are valid points on the faces of the detector
    for i in range(6):
        if (faces[i].x <= x_max) & (faces[i].x >= x_min) & (faces[i].y <= y_max) & (faces[i].y >= y_min) & (
                faces[i].z <= z_max) & (faces[i].z >= z_min):
            valid_points.append(faces[i])
            valid_lambdas.append(lambdas[i])

    # add valid points to entries and exit lists if found
    if len(valid_points) == 2:
        # check which is entry and exit
        if valid_lambdas[0] < valid_lambdas[1]:
            entry = valid_points[0]
            exit = valid_points[1]
            entries.append(valid_points[0])
            exits.append(valid_points[1])
        else:
            entry = valid_points[1]
            exit = valid_points[0]
            entries.append(valid_points[1])
            exits.append(valid_points[0])
    elif len(valid_points) == 1 or len(valid_points) > 2:
        print('invalid number of trajectory entry/exit points')

    # ----------------------SAMPLE SPEED------------------------------------
    # v_bar most likely needs refined
    v_bar = np.c * (10 ** -3)

    # each component sampled from a normal distribution with mean 0 and standard deviation v_bar/sqrt(3)
    v_x = np.random.normal(0, v_bar/np.sqrt(3))
    v_y = np.random.normal(0, v_bar/np.sqrt(3))
    v_z = np.random.normal(0, v_bar/np.sqrt(3))

    # find magnitude of velocity
    speed = np.sqrt((v_x ** 2) + (v_y ** 2) + (v_z ** 2))
    speeds.append(speed)

    # create a normalized trajectory vector
    traj_vect = urm.TVector3(exit.x - entry.x, exit.y - entry.y, exit.z - entry.z)
    traj_vect_norm = traj_vect / np.sqrt((traj_vect.x ** 2) + (traj_vect.y ** 2) + (traj_vect.z ** 2))

    # construct velocity vector from trajectory and speed
    cur = len(exits)
    velocity = speed * traj_vect_norm

    # -----------------------------------------INTERACTION--------------------------------------
    # cross-section taken from figure 7 of DM nucleus capture paper
    cross_section = 10 ** -25

    # radiative capture radius
    # derived from eq 32 of DM nucleus capture paper
    r_phi = (((cross_section * speed)/(60 * (10 ** -3))) ** 2) * (10 ** 5)

    # calculation of number density
    # molar mass of target -- in case of DUNE this is liquid argon
    molar_mass_target = 39.948  # g/mol
    # mass density of target -- in case of DUNE this is liquid argon
    mass_density_target = 1.3982    # g/L (at boiling point)
    # number density of target
    number_density_target = (np.Avogadro * mass_density_target) / molar_mass_target

    # to track total sampled distance along trajectory
    tot_dist = 0
    # to track all the interaction points sampled
    all_inter_pts = []

    # continue looping until reach break statement i.e. until sampled point leaves the detector
    while 1:
        # sample distance along trajectory until interaction
        y = np.random.random()
        dist = -(1/(number_density_target * cross_section)) * np.log(1 - y)
        tot_dist = tot_dist + dist

        # find point along trajectory from sampled distance
        inter_pt = entry + tot_dist * traj_vect_norm
        all_inter_pts.append(inter_pt)

        # if the interaction point is within the bounds of the detector
        if (inter_pt.x <= x_max) & (inter_pt.x >= x_min) & (inter_pt.y <= y_max) & (inter_pt.y >= y_min) & (inter_pt.z <= z_max) & (inter_pt.z >= z_min):
            # --------------------------------------SCATTERING-------------------------------------
            # ---------------------------PART 1-----------------------------------------
            # incoming beam particle and stationary target particle
            # construct 4 vector momentum using known energy and momentum

            # target particle (stationary)
            mass_target = 6.6335209 * (10 ** -26)    # in the case of DUNE this is argon
            target = urm.TLorentzVector(mass_target, 0, 0, 0)

            # beam particle (dark matter)
            mass_DM = (10 ** 20.5) * (1.7826 * (10 ** -27))   # converted from Gev to kg
            gamma = 1 / np.sqrt(1 - speed ** 2)
            p_beam = gamma * velocity
            p_mag_beam = np.sqrt((p_beam.x ** 2) + (p_beam.y ** 2) + (p_beam.z ** 2))
            beam = urm.TLorentzVector(np.sqrt((p_mag_beam ** 2) + mass_DM ** 2), p_beam.x, p_beam.y, p_beam.z)

            # ---------------------------PART 2---------------------------------------
            # apply lorentz boost s.t. sum of incoming four-momentum equals zero
            boost_factor = urm.TVector3(beam.x + target.x, beam.y + target.y, beam.z + target.z) / -(beam.E + target.E)

            target_boosted = target.boost(boost_factor)
            beam_boosted = beam.boost(boost_factor)

            # ---------------------------PART 3--------------------------------------
            # solve for 4 momenta for outgoing particles

            # the binding energy coming from the argon/DM bound state
            # this is currently approximated to be 1/r_phi but may need adjusted later on
            E_binding_bound_state = 1 / r_phi

            # masses of outgoing particles
            mass_out_photon = 0
            mass_out_DM = mass_DM + mass_target - E_binding_bound_state

            # total energy of center of mass frame
            E_cm = beam_boosted.E + target_boosted.E

            # energy of outgoing particles
            E_out_photon = (E_cm ** 2 + mass_out_photon ** 2 - mass_out_DM ** 2) / (2 * E_cm)
            E_out_DM = (E_cm ** 2 + mass_out_DM ** 2 - mass_out_photon ** 2) / (2 * E_cm)

            # solve for magnitudes of two momenta
            p_photon_abs = p_DM_abs = np.sqrt(E_out_photon ** 2 - mass_out_photon ** 2)

            # sample c uniformly from -1 to 1
            # could potentially be impacted by differential cross-section but will reassess this later on
            c_out = 2.0 * np.random.random() - 1.0
            # sample phi(polar angle) uniformly from 0 to 2pi
            phi_out = 2.0 * np.pi * np.random.random()

            # construct four-vector momenta in boosted frame
            out_photon_boosted = urm.TLorentzVector(E_out_photon, p_photon_abs * np.sqrt(1 - c_out ** 2) * np.cos(phi_out), p_photon_abs * np.sqrt(1 - c_out ** 2) * np.sin(phi_out), p_photon_abs * c_out)
            out_DM_boosted = urm.TLorentzVector(E_out_DM, -p_photon_abs * np.sqrt(1 - c_out ** 2) * np.cos(phi_out), -p_photon_abs * np.sqrt(1 - c_out ** 2) * np.sin(phi_out), -p_photon_abs * c_out)

            # ----------------------------------PART 4---------------------------------------
            # boost back to lab frame using inverse boost parameter
            inverse_boost_factor = -boost_factor

            out_photon = out_photon_boosted.boost(inverse_boost_factor)
            out_DM = out_DM_boosted.boost(inverse_boost_factor)
        else:
            break   # if the sampled point is not in the detector break the loop


from datetime import datetime
from pyelasticsearch import ElasticSearch
from dbconnect import *

import argparse
import json
import os

es = ElasticSearch()

ap = argparse.ArgumentParser()
ap.add_argument("-d", "--date", required = True, help = "date to index")
args = vars(ap.parse_args())

ad_mapping = {
    'ad': {
        'properties': {
            'channelId': {'type': 'integer'},
            'channelName': {'type': 'string'},
            'adId': {'type': 'integer'},
            'adUrl': {'type': 'string'},
            'adType': {'type': 'string'},
            'adSize': {'type': 'string'},
            'dateCreated': {'type': 'date', 'format' : 'YYYY-MM-dd HH:mm:ss'},
            'websiteId': {'type': 'integer'},
            'website': {'type': 'string', 'analyzer': 'simple'},
            'category': {'type': 'string'},
            'subCategory': {'type': 'string'}
        }
    }
}

es.health(wait_for_status='yellow')
es.delete_index('write-ads')
es.create_index('write-ads', settings={'mappings': ad_mapping})

dateYMD = args["date"]
prepareDataFromDB(dateYMD)

dir = DATA_FILES_JSON + '/' + dateYMD
for filename in os.listdir(dir):
    if filename.endswith('.json'):
        with open(dir + '/' + filename) as open_file:
            json_docs = json.load(open_file)
            es.bulk((es.index_op(doc) for doc in json_docs),
                index='write-ads',
                doc_type='ad')

es.refresh("write-ads")

res = es.search('website:com', index='write-ads')
print("Got %d Hits for .com websites" % res['hits']['total'])
for hit in res['hits']['hits']:
    print (hit["_source"])
res = es.search('website:in', index='write-ads')
print("Got %d Hits for .in websites" % res['hits']['total'])
res = es.search('category:entertainment', index='write-ads')
print("Got %d Hits for category:Entertainment" % res['hits']['total'])


def isPalindrome(s: str):
    left = 0
    right = len(s) - 1
    s = s.lower()
    while left < right:
        if not s[left].isalnum():
            left += 1
            continue
        if not s[right].isalnum():
            right -= 1
            continue
        if s[left] != s[right]:
            return False
        left += 1
        right -= 1
    return True

print(isPalindrome("A man, a plan, a canal: Panama"))


import pandas as pd
from packaging import version
from typing import Union, List

is_deprecated_lexsorted_pandas = version.parse(pd.__version__) > version.parse("1.3.0")

def get_level_index(df: pd.DataFrame, level=Union[str, int]) -> int:
    if isinstance(level, str):
        try:
            return df.index.names.index(level)
        except (AttributeError, ValueError):
            return ("datetime", "instrument").index(level)
    elif isinstance(level, int):
        return level
    else:
        raise NotImplementedError(f"This type of input is not supported")

def lazy_sort_index(df: pd.DataFrame, axis=0) -> pd.DataFrame:
    idx = df.index if axis == 0 else df.columns
    if (
        not idx.is_monotonic_increasing
        or not is_deprecated_lexsorted_pandas
        and isinstance(idx, pd.MultiIndex)
        and not idx.is_lexsorted()
    ):  # this case is for the old version
        return df.sort_index(axis=axis)
    else:
        return df

def fetch_df_by_index(
    df: pd.DataFrame,
    selector: Union[pd.Timestamp, slice, str, list, pd.Index],
    level: Union[str, int],
    fetch_orig=True,
) -> pd.DataFrame:
    # level = None -> use selector directly
    if level is None or isinstance(selector, pd.MultiIndex):
        return df.loc(axis=0)[selector]
    # Try to get the right index
    idx_slc = (selector, slice(None, None))
    if get_level_index(df, level) == 1:
        idx_slc = idx_slc[1], idx_slc[0]
    if fetch_orig:
        for slc in idx_slc:
            if slc != slice(None, None):
                return df.loc[
                    pd.IndexSlice[idx_slc],
                ]
        else:  # pylint: disable=W0120
            return df
    else:
        return df.loc[
            pd.IndexSlice[idx_slc],
        ]

def fetch_df_by_col(df: pd.DataFrame, col_set: Union[str, List[str]]) -> pd.DataFrame:

    if not isinstance(df.columns, pd.MultiIndex) or col_set == '__raw':
        return df
    elif col_set =='__all':
        return df.droplevel(axis=1, level=0)
    else:
        return df.loc(axis=1)[col_set]


# Output all the prime multiplers of the given number and the degrees.

k = int(input())

A = []
for i in range(2, k + 1):
    bool = True
    if k % i == 0:
        for j in range(2, i):
            if i % j == 0:
                bool = False
                break
        if bool == True: A.append(i)

print(A)
for i in A:
    m = k
    count = 0
    while m % i == 0:
        count += 1
        m /= i
    print(f'({i}, {count})')


from requests import get
from bs4 import BeautifulSoup

def main():
    res = get(
        "https://medium.com/towards-data-science/the-5-basic-statistics-concepts-data-scientists-need-to-know-2c96740377ae"
    )

    soup = BeautifulSoup(res.content, "html.parser")
    h1s = soup.find_all(name="h1", recursive=True)
    print()

    for h1 in h1s:
        print(h1.getText())

if __name__ == "__main__":
    main()


from AutomationToolsLib import Logging, AutomationPreferences, SlackNotification
from datetime import date
from xml.etree import ElementTree
from sys import exit

try:
    import requests
except:
    print(
        "The requests module is not installed. To install the request module, use the pip3 command: pip3 install requests"
    )
    exit

def GetUpdatedSoftwareVersion():
    logPrefs = AutomationPreferences("LOG_LOCATION")
    tDate = str(date.today())
    newPackageFile = open(logPrefs["LOG_LOCATION"] + "/newpackage.log", "r")
    softwareUpdates = {}
    for line in newPackageFile:
        if tDate in line:
            for software in newPackageFile:
                if "updated software:" in software:
                    software = software.strip("updated software: ")
                    software = software.rstrip("\n")
                    software = software.rsplit(sep=" ", maxsplit=1)
                    softwareUpdates[software[0]] = software[1]
    return softwareUpdates

def AddPackageToDefinition(updatedSoftware):
    logfile = "jamfPatchUpdate.log"
    jamfPrefs = AutomationPreferences("JSS_URL", "API_USERNAME", "API_PASSWORD")
    patchURL = jamfPrefs["JSS_URL"] + "/JSSResource/patchsoftwaretitles"
    pkgSuffix = ".pkg"
    pkgList = []
    for pkg in updatedSoftware:
        pkgList.append(pkg + "-" + updatedSoftware[pkg] + pkgSuffix)
    response = requests.get(
        patchURL,
        auth=(jamfPrefs["API_USERNAME"], jamfPrefs["API_PASSWORD"]),
        headers={"Accept": "application/xml"},
    )
    if response.status_code != 200:
        Logging(logfile, "Error connecting to Jamf: " + str(response.status_code))
        Logging(logfile, str(response.content))
        exit()
    responseTree = ElementTree.fromstring(response.content)
    for software in updatedSoftware:
        iterator = 1
        software_not_found = False
        while iterator <= int(responseTree[0].text):
            if software == responseTree[iterator][0].text:
                Logging(logfile, "Updating patch policy for " + software)
                patchTitleResponse = requests.get(
                    patchURL + "/id/" + responseTree[iterator][1].text,
                    auth=(jamfPrefs["API_USERNAME"], jamfPrefs["API_PASSWORD"]),
                    headers={"Accept": "application/xml"},
                )
                if patchTitleResponse.status_code != 200:
                    Logging(
                        logfile,
                        "There was an error in retrieving XML: "
                        + str(response.status_code),
                    )
                    Logging(logfile, str(patchTitleResponse.content))
                    Logging(logfile, patchURL + "/id/" + responseTree[iterator][1].text)
                else:
                    try:
                        patchTitleTree = ElementTree.fromstring(
                            patchTitleResponse.content
                        )
                        if patchTitleTree[6][0][0].text == updatedSoftware[software]:
                            for pkg in pkgList:
                                if updatedSoftware[software] in pkg:
                                    xmlData = (
                                        "<patch_software_title><versions><version><software_version>"
                                        + updatedSoftware[software]
                                        + "</software_version><package><name>"
                                        + pkg
                                        + "</name></package></version></versions></patch_software_title>"
                                    )
                                    newResponse = requests.put(
                                        patchURL
                                        + "/id/"
                                        + responseTree[iterator][1].text,
                                        auth=(
                                            jamfPrefs["API_USERNAME"],
                                            jamfPrefs["API_PASSWORD"],
                                        ),
                                        data=xmlData,
                                        headers={"content-type": "application/xml"},
                                    )
                                    if newResponse.status_code != 201:
                                        Logging(
                                            logfile,
                                            "Update of "
                                            + software
                                            + " failed with error code: "
                                            + str(newResponse.status_code),
                                        )
                                        Logging(logfile, newResponse.content)
                                    else:
                                        Logging(
                                            logfile,
                                            pkg
                                            + " added to definition version "
                                            + updatedSoftware[software],
                                        )
                                        # UpdateTargetVersion(updatedSoftware[software])
                                    iterator = int(responseTree[0].text) + 50
                        else:
                            Logging(
                                logfile,
                                "Updated Version does not match the latest version in Jamf.",
                            )
                            Logging(
                                logfile,
                                "Jamf: "
                                + str(patchTitleTree[6][0][0].text)
                                + " != "
                                + "Updated: "
                                + updatedSoftware[software],
                            )
                            iterator = int(responseTree[0].text) + 50
                    except:
                        Logging(logfile, "There was a problem with the XML content")
                        Logging(logfile, str(patchTitleResponse.content))
                        Logging(
                            logfile, patchURL + "/id/" + responseTree[iterator][1].text
                        )
                        Logging(logfile, xmlData)
            iterator = iterator + 1
            if iterator == int(responseTree[0].text):
                software_not_found = True
        if software_not_found:
            Logging(
                logfile,
                "No patch policy found for "
                + software
                + " "
                + str(updatedSoftware[software]),
            )
            print(
                "No patch policy found for "
                + software
                + " "
                + str(updatedSoftware[software])
            )

def UpdateTargetVersion(updatedSoftware):
    logfile = "jamfPatchUpdate.log"
    apiPrefs = AutomationPreferences("API_USERNAME", "API_PASSWORD", "JSS_URL")
    apiURL = apiPrefs["JSS_URL"] + "/JSSResource/patchpolicies"
    response = requests.get(
        apiURL,
        auth=(apiPrefs["API_USERNAME"], apiPrefs["API_PASSWORD"]),
        headers={"Accept": "application/xml"},
    )
    patchPolicyContent = ElementTree.fromstring(response.content)
    for software in updatedSoftware:
        counter = 1
        Logging(logfile, "Updating target version for " + software)
        for title in patchPolicyContent:
            while counter <= int(patchPolicyContent[0].text):
                softwareTestPolicy = software + " Update Test"
                if softwareTestPolicy == patchPolicyContent[counter][1].text:
                    patchPolicyID = patchPolicyContent[counter][0].text
                    xmlData = (
                        "<patch_policy><general><target_version>"
                        + updatedSoftware[software]
                        + "</target_version></general></patch_policy>"
                    )
                    patchTrgtResponse = requests.put(
                        apiURL + "/id/" + patchPolicyID,
                        auth=(apiPrefs["API_USERNAME"], apiPrefs["API_PASSWORD"]),
                        data=xmlData,
                        headers={"Content-type": "application/xml"},
                    )
                    if patchTrgtResponse.status_code != 201:
                        Logging(
                            logfile,
                            software
                            + " target version update failed with response code: "
                            + str(patchTrgtResponse.status_code),
                        )
                        Logging(
                            logfile,
                            software
                            + " target version "
                            + updatedSoftware[software]
                            + " was not updated to "
                            + patchPolicyContent[counter][1].text,
                        )
                        SlackNotification(
                            logfile,
                            ":failed: "
                            + patchPolicyContent[counter][1].text
                            + " was not updated. Please update "
                            + patchPolicyContent[counter][1].text
                            + " to "
                            + updatedSoftware[software]
                            + " manually.",
                        )
                    else:
                        Logging(
                            logfile,
                            patchPolicyContent[counter][1].text
                            + " has been updated to target version "
                            + updatedSoftware[software],
                        )
                        SlackNotification(
                            logfile,
                            ":white_check_mark: "
                            + patchPolicyContent[counter][1].text
                            + " has been updated to target version "
                            + updatedSoftware[software],
                        )
                    counter = int(patchPolicyContent[0].text) + 1
                else:
                    counter = counter + 1
            if counter == int(patchPolicyContent[0].text):
                Logging(logfile, softwareTestPolicy + " wasn't found.")

def Main():
    logfile = "jamfPatchUpdate.log"
    todayDate = str(date.today())
    Logging(logfile, "********************" + str(todayDate) + "********************")
    softwareUpdate = GetUpdatedSoftwareVersion()
    if len(softwareUpdate) != 0:
        AddPackageToDefinition(softwareUpdate)
        UpdateTargetVersion(softwareUpdate)
    else:
        Logging(logfile, "No new software updates.")

Main()


class Solution:
    def spiralOrder(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: List[int]
        """
        start_n = 0
        end_n = len(matrix) - 1
        start_m = 0
        end_m = len(matrix[0]) - 1 if len(matrix) > 0 else - 1
        result = []

        while start_n <= end_n and start_m <= end_m:
            # Go across the top of the matrix
            for i in range(start_m, end_m + 1):
                result.append(matrix[start_n][i])
            start_n += 1

            # Go down the right of the matrix
            for i in range(start_n, end_n + 1):
                result.append(matrix[i][end_m])
            end_m -= 1

            # Go back along the bottom
            if start_n <= end_n:
                for i in range(end_m, start_m - 1, -1):
                    result.append(matrix[end_n][i])
                end_n -= 1

            # Go up along the left
            if start_m <= end_m:
                for i in range(end_n, start_n - 1, -1):
                    result.append(matrix[i][start_m])
                start_m += 1
        return result


import os

__location__ = os.path.realpath(
    os.path.join(os.getcwd(), os.path.dirname(__file__)))
f = open(os.path.join(__location__, 'input.txt'))

abc = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

sum = 0
for line in f:
    shared = []
    line = line.rstrip()

    print(f"\n{line}")

    n = len(line) // 2
    if len(line) == 0:
        continue

    first = line[0:n]
    second = line[n:]
    print(f"{first} {second}")

    for i in first:
        if i in second and i not in shared:
                shared.append(i)

    if len(shared) > 0:
        for i in shared:
            priority = abc.find(i) + 1
            sum += priority
            print(f"{shared} = {priority}")
            print(f"sum = {sum}")