# coding=utf-8
import time

from test.tendao.common.ReadConfig import getConfigInfo
from selenium import webdriver
from test.tendao.common.CapPicture import capPicture
from test.tendao.common.LogTool import getLogger
'''
根据不同的浏览器名称判断来启动不同的浏览器驱动
'''

# 获取日志对象
log = getLogger('BrowserStart')

# 获取浏览器名称
browser_name = getConfigInfo('browser','BrowserName')
# 获取浏览器请求的url
url = getConfigInfo('browser','Url')

if browser_name == 'Chrome':
    log.info('启动Chrome浏览器')
    driver = webdriver.Chrome()

    log.info('请求网页：'+url)
    driver.get(url)

if browser_name == 'IE':
    driver = webdriver.Ie()
    driver.get(url)
# 进行截图
capPicture(driver)

time.sleep(3)
driver.quit()
log.info('关闭浏览器')


"""Product tests module."""

from decimal import Decimal

from django.db.utils import IntegrityError
from django.test import TransactionTestCase
from mixer.backend.django import mixer

from app.models import Product

class ProductTestCase(TransactionTestCase):
    """Product TestCase"""

    def test_create_model_with_valid_data(self):
        """Create model with valid data should work as expected."""
        product = mixer.blend(
            Product,
            description="Bolacha de Água e Sal",
            unit_price=Decimal(2.6),
            commission_percentage=Decimal(2.75),
        )

        self.assertEqual(product.description, "Bolacha de Água e Sal")
        self.assertEqual(product.unit_price, Decimal(2.6))
        self.assertEqual(product.commission_percentage, Decimal(2.75))

    def test_create_model_with_invalid_data(self):
        """Create model with valid data should work as expected."""
        valid_description = "Suco de manga"
        valid_unit_price = Decimal(9.85)
        valid_commission_percentage = Decimal(3.0)

        with self.subTest("Create Product without description should raise exception."):
            with self.assertRaises(IntegrityError):
                Product.objects.create(  # pylint: disable=no-member
                    description=None,
                    unit_price=valid_unit_price,
                    commission_percentage=valid_commission_percentage,
                )

        with self.subTest("Create Product without unit_price should raise exception."):
            with self.assertRaises(IntegrityError):
                Product.objects.create(  # pylint: disable=no-member
                    description=valid_description,
                    unit_price=None,
                    commission_percentage=valid_commission_percentage,
                )

        with self.subTest(
            "Create Product without commission_percentage should raise exception."
        ):
            with self.assertRaises(IntegrityError):
                Product.objects.create(  # pylint: disable=no-member
                    description=valid_description,
                    unit_price=valid_unit_price,
                    commission_percentage=None,
                )

        with self.subTest(
            "Create Product with unit_price negative should raise exception."
        ):
            with self.assertRaises(IntegrityError):
                Product.objects.create(  # pylint: disable=no-member
                    description=valid_description,
                    unit_price=-1.87,
                    commission_percentage=valid_commission_percentage,
                )

        with self.subTest(
            "Create Product with commission_percentage negative should raise exception."
        ):
            with self.assertRaises(IntegrityError):
                Product.objects.create(  # pylint: disable=no-member
                    description=valid_description,
                    unit_price=valid_unit_price,
                    commission_percentage=-2,
                )

    def test_str_method(self):
        """Test str method of Model."""
        product = mixer.blend(
            Product,
            description="Batata Frita",
            unit_price=4.45,
            commission_percentage=1,
        )
        self.assertEqual(str(product), "Batata Frita")


# coding: utf-8

__author__ = "lau.wenbo"

"""
你有一个用于表示一片土地的整数矩阵land，该矩阵中每个点的值代表对应地点的海拔高度。

若值为0则表示水域。由垂直、水平或对角连接的水域为池塘。池塘的大小是指相连接的水域的个数。

编写一个方法来计算矩阵中所有池塘的大小，返回值需要从小到大排序。

示例：

输入：
[
  [0,2,1,0],
  [0,1,0,1],
  [1,1,0,1],
  [0,1,0,1]
]
输出： [1,2,4]

"""

import collections

class Solution:
    def pondSizes(self, land):
        res = []
        for row in range(len(land)):
            for col in range(len(land[0])):
                if land[row][col] == 0:
                    tmp = collections.deque()
                    tmp_count = 1
                    land[row][col] = -1  # 将访问的点标记进行标记
                    tmp.append([row, col])
                    while len(tmp) > 0:
                        x, y = tmp.popleft()
                        # 注意题目要求，斜向也要算，所以一共是 8 个方向
                        for new_x, new_y in [[x + 1, y], [x - 1, y], [x, y + 1], [x, y - 1],
                                             [x - 1, y - 1], [x - 1, y + 1], [x + 1, y + 1], [x + 1, y - 1]]:
                            if 0 <= new_x < len(land) and 0 <= new_y < len(land[0]) and land[new_x][new_y] == 0:
                                tmp_count += 1
                                land[new_x][new_y] = -1
                                tmp.append([new_x, new_y])
                    res.append(tmp_count)
        return sorted(res)


import uuid

from django import forms
from django.db.models import Field
from django.utils.encoding import smart_str

try:
    # psycopg2 needs us to register the uuid type
    #import psycopg2
    #psycopg2.extras.register_uuid()
    pass #TODO!
except (ImportError, AttributeError):
    pass

class StringUUID(uuid.UUID):
    def __unicode__(self):
        return self.hex

    def __str__(self):
        return self.hex

    def __len__(self):
        return len(self.__unicode__())

class UUIDField(Field):
    """
    A field which stores a UUID value in hex format. This may also have
    the Boolean attribute 'auto' which will set the value on initial save to a
    new UUID value (calculated using the UUID1 method). Note that while all
    UUIDs are expected to be unique we enforce this with a DB constraint.
    """

    def __init__(self, version=4, node=None, clock_seq=None,
            namespace=None, name=None, auto=False, *args, **kwargs):
        assert version in (1, 3, 4, 5), "UUID version %s is not supported." % version
        self.auto = auto
        self.version = version
        # We store UUIDs in hex format, which is fixed at 32 characters.
        kwargs['max_length'] = 32
        if auto:
            # Do not let the user edit UUIDs if they are auto-assigned.
            kwargs['editable'] = False
            kwargs['blank'] = True
            kwargs['unique'] = True
        if version == 1:
            self.node, self.clock_seq = node, clock_seq
        elif version in (3, 5):
            self.namespace, self.name = namespace, name
        super(UUIDField, self).__init__(*args, **kwargs)

    def _create_uuid(self):
        if self.version == 1:
            args = (self.node, self.clock_seq)
        elif self.version in (3, 5):
            error = None
            if self.name is None:
                error_attr = 'name'
            elif self.namespace is None:
                error_attr = 'namespace'
            if error is not None:
                raise ValueError("The %s parameter of %s needs to be set." %
                                 (error_attr, self))
            if not isinstance(self.namespace, uuid.UUID):
                raise ValueError("The name parameter of %s must be an "
                                 "UUID instance." % self)
            args = (self.namespace, self.name)
        else:
            args = ()
        return getattr(uuid, 'uuid%s' % self.version)(*args)

    def db_type(self, connection=None):
        """
        Return the special uuid data type on Postgres databases.
        """
        if connection and 'postgres' in connection.vendor:
            return 'uuid'
        return 'char(%s)' % self.max_length

    def pre_save(self, model_instance, add):
        """
        This is used to ensure that we auto-set values if required.
        See CharField.pre_save
        """
        value = getattr(model_instance, self.attname, None)
        if self.auto and add and not value:
            # Assign a new value for this attribute if required.
            uuid = self._create_uuid()
            setattr(model_instance, self.attname, uuid)
            value = uuid.hex
        return value

    def get_db_prep_value(self, value, connection, prepared=False):
        """
        Casts uuid.UUID values into the format expected by the back end
        """
        if isinstance(value, uuid.UUID):
            return str(value)
        return value

    def value_to_string(self, obj):
        val = self._get_val_from_obj(obj)
        if val is None:
            data = ''
        else:
            data = str(val)
        return data

    def to_python(self, value):
        """
        Returns a ``StringUUID`` instance from the value returned by the
        database. This doesn't use uuid.UUID directly for backwards
        compatibility, as ``StringUUID`` implements ``__unicode__`` with
        ``uuid.UUID.hex()``.
        """
        if not value:
            return None
        # attempt to parse a UUID including cases in which value is a UUID
        # instance already to be able to get our StringUUID in.
        return StringUUID(smart_text(value))

    def formfield(self, **kwargs):
        defaults = {
            'form_class': forms.CharField,
            'max_length': self.max_length,
        }
        defaults.update(kwargs)
        return super(UUIDField, self).formfield(**defaults)

try:
    from south.modelsinspector import add_introspection_rules
    add_introspection_rules([], [r"^uuidfield\.fields\.UUIDField"])
except ImportError:
    pass


#coding=UTF-8
'''
Created on 2011-7-10

@author: Administrator
'''
import wx
from ui.window import create
class uiApp(wx.App):
    def OnInit(self):
        self.main = create(None)
        self.main.Show()
        self.SetTopWindow(self.main)
        return True

def main():
    application = uiApp(0)
    application.MainLoop()

if __name__ == '__main__':
    main()


from django.conf import settings
from django.conf.urls.static import static
from django.urls import path
from . import views

app_name = 'posts'
urlpatterns = [
    path('', views.index, name='blog'),
    path('<int:pk>/', views.PostDetailView.as_view(), name='post details'),
    path('<int:pk>/update/', views.PostUpdateView.as_view(), name='post update'),
    path('new_post/', views.new_post, name='new post'),
    path('my_posts/', views.my_posts, name='my posts'),
    path('successful_new_request/', views.successful_new_request, name='successful new post'),
    path('personal_account/', views.personal_account, name='personal account'),
]


#!/usr/bin/python3

from django.shortcuts import render, redirect, get_object_or_404
from django.core import serializers
from django.http import JsonResponse
from django.contrib import messages
from django.db.models import Max

from parametros.views import (ViewListView,
        ViewCreateView,
        ViewUpdateView,
        ViewDeleteView,
        )

from .models import (PeriodoProfesorModulo,
        Horario,
        HorarioTemp,
        ReservaBloqueProtegido,
        CursosGrupo,
        )

from parametros.models import (Periodo,
        Plan,
        Profesor,
        Modulo,
        ModuloEspejo,
        Carrera,
        Bloque,
        Actividad,
        )

from .forms import (PeriodoProfesorModuloForm,
        ReservaBloqueProtegidoForm,
        CursosGrupoForm,
        )

from django.views.generic.base import TemplateView
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse

from .valida import (valida_cantidad_horas,
        valida_choque_horario_profesor,
        valida_choque_horario_modulo_semestre,
        # valida_ppm_horario,
        valida_existe_grupos_cursos,
        )
import json
import collections

# Create your views here.

dic_dia_semana={"1": "Lunes",
        "2":"Martes",
        "3":"Miercoles",
        "4":"Jueves",
        "5":"Viernes",
        }

from parametros.views import StaffRequiredMixin

def create_dic_bloque():
    """
    Crea diccionario con todos los elementos de la clase bloque.
    Esto crea dos elementos uno de tipo string (key) y otro el tipo
    diccionario (value), que a su vez contiene la key de bloque y value
    por defecto como falso.
    ejemplo, dic={key:value{xx:vv}}

    Retorna:
        * Dic: Diccionario de datos
    """
    dia_semana = collections.OrderedDict(sorted(dic_dia_semana.items()))
    b = Bloque.objects.all().order_by("nombre")
    p = ReservaBloqueProtegido.objects.all()

    dic={}

    for i in dia_semana:
        dic_aux={}

        for t in b:
            dic_aux[t]= False

        for t in p:
            dic_aux[t.bloque]="X"
        dic[i]=dic_aux

    dic = collections.OrderedDict(sorted(dic.items()))

    return dic

def create_dic_bloque_title(context):
    """
    Crea los titulos y extensión de los bloques para ser dibujado en la tabla
    que realiza la interacción con el horario.
    Recibe:
        Objeto de tipo context (diccionario)
    Retorna:
        Objeto de tipo context (diccionario)
    """

    b = Bloque.objects.all().order_by("nombre")
    context["bloque_list"] = b

    #max de bloque
    b = b.aggregate(Max("nombre"))
    b = b["nombre__max"]
    context["bloque_max"] = range(0, b)

    return context

def create_dic_cursos_grupo(periodo):
    """
    Crea un diccionario con los objectos obtenidos de acuerdo a un periodo
    determinado

    Recibe:
        * Integer: codigo periodo

    Retorna:
        diccionario del modo:
        {
            codigo_periodo: [CursosGrupo, CursosGrupo, ...]
        }
    """

    cg = CursosGrupo.objects
    cg_values = cg.values('modulo').filter(periodo__id = periodo)
    cg_values = cg_values.distinct()

    cg_query = cg.all().filter(periodo__id = periodo)

    dic = {}
    aux = []

    for i in cg_values:
        for t in cg_query.filter(modulo__id=i['modulo']):
            aux.append(t)
        dic[i["modulo"]] = aux
        aux = []

    return dic

class PeriodoProfesorModuloListView(StaffRequiredMixin, ViewListView):
    model = PeriodoProfesorModulo
    template_name = "horario/base_horario.html"
    titulo = "Asignación Profesor Módulo"
    extra_context = {}

    def get_context_data(self, *args, **kwargs):

        context = super(PeriodoProfesorModuloListView, self).get_context_data(*args, **kwargs)

        periodo = self.request.GET.get("periodo")
        carrera = self.request.GET.get("carrera")
        plan = self.request.GET.get("plan")

        c = Carrera.objects.all().order_by("nombre")
        context['carrera'] = c

        if carrera is None or carrera == 0:
            queryset = None

        else:
            #habilito el select de periodo
            p = Periodo.objects.all().order_by("-nombre")
            context['periodo'] = p

            #habilito select de plan
            pl = Plan.objects.all().filter(carrera = carrera)
            pl = pl.order_by("-nombre")
            context["plan"] = pl

        if carrera is not None and carrera !=0:
            #filtro el query por carrera para ser listado
            queryset = PeriodoProfesorModulo.objects.all()
            queryset = queryset.filter(carrera=carrera)

        if periodo is not None and periodo !=0:
            # filtro el query por periodo
            # el resultando es de carrera + periodo
            queryset = queryset.filter(periodo=periodo)

        if plan is not None and plan !=0:
            #filtro el query por plan
            #el resultante es filtro de carrera + plan
            queryset = queryset.filter(plan=plan)

        context['object_list'] = queryset

        return context

class PeriodoProfesorModuloCreateView(StaffRequiredMixin, ViewCreateView):
    form_class = PeriodoProfesorModuloForm
    template_name = "horario/form_ppm.html"
    titulo = "Agrega Asignacion de periodo-profesor-modulo"
    success_message = "La Asignacion %(nombre)s ha sido creado"
    success_url = "/periodoprofesormodulo/"

    def get_context_data(self, **kwargs):

        context = super(PeriodoProfesorModuloCreateView, self).get_context_data(**kwargs)

        dic=create_dic_bloque()

        context["horario"] = dic
        context["dia_semana_list"] = dic_dia_semana

        create_dic_bloque_title(context)

        return context

    def get_success_message(self, cleaned_data):
        """
        cleaned_data is the cleaned data from the form which is used for string
        formatting
        """
        return self.success_message % dict(cleaned_data,
                nombre=self.object.profesor.nombre)

        def form_valid(self, form):
            form.save()
        ppm = form.instance
        #Aca se debe guardar el temporal
        a = HorarioTemp.objects.all()
        a = a.filter(modulo = ppm.modulo,
                carrera = ppm.carrera,
                profesor = ppm.profesor,
                )
        for i in a:
            h = Horario(periodoprofesormodulo = ppm,
                    dia_semana = i.dia_semana,
                    bloque = i.bloque,
                    actividad = i.actividad,
                    reservado = True,
                    )
            h.save()
            i.delete()

        return super(PeriodoProfesorModuloCreateView, self).form_valid(form)

class PeriodoProfesorModuloUpdateView(StaffRequiredMixin, ViewUpdateView):
    model = PeriodoProfesorModulo
    form_class = PeriodoProfesorModuloForm
    template_name = "horario/form_ppm.html"
    success_message = "El Profesor %(nombre)s ha sido actualizado"
    success_url = "/periodoprofesormodulo/"
    titulo = "Edita Asignacion de periodo-profesor-modulo"

    def get_context_data(self, **kwargs):

        context = super(PeriodoProfesorModuloUpdateView, self).get_context_data(**kwargs)
        context["dia_semana_list"] = dic_dia_semana

        h = None
        ppm = context["object"]

        if (ppm is not None):
            h = Horario.objects.all().filter(periodoprofesormodulo = ppm)
            h = h.order_by("dia_semana", "bloque__nombre")

            cg = CursosGrupo.objects.all()
            cg = cg.filter(periodo = ppm.periodo,
                    modulo = ppm.modulo)
            context["cursosgrupo"] = cg

        dic=create_dic_bloque()

        for i in h:
            """
            Actualizo los elementos del diccionario creado, esto es solo para
            los elementos que se encuentran en la clase horario.
            """
            x=dic[i.dia_semana]
            """
            Chequea si el modulo esta disponible o no
            Si reservado es Falso, la actividad es None o Null,
            Si reservado es Verdadero, la actividad tiene un objeto de tipo
            Actividad, y en este caso se asocia al identificador para poder
            mostrar en la tabla de horario de PPM
            """
            if (i.reservado is True):
                xx = x[i.bloque]=i.actividad.identificador

        context["horario"] = dic
        context = create_dic_bloque_title(context)
        create_dic_bloque_title(context)

        return context

    def get_success_message(self, cleaned_data):
        #cleaned_data is the cleaned data from the form which is used for string formatting
        return self.success_message % dict(cleaned_data,
                nombre=self.object.profesor.nombre)

class PeriodoProfesorModuloDeleteView(StaffRequiredMixin, ViewDeleteView):
    model = PeriodoProfesorModulo
    template_name = "parametros/elimina.html"
    success_message = 'El Profesor %(nombre)s ha sido Eliminado'
    success_url = "/periodoprofesormodulo/"

    # def delete(self, request, *args, **kwargs):
    #     object = self.get_object()
    #     messages.success(self.request, self.success_message %dict(nombre=object,))
    #     return super(PeriodoProfesorModuloDeleteView, self).delete(request, *args, **kwargs)

class ReservaBloqueProtegidoListView(StaffRequiredMixin, ViewListView):
    model = ReservaBloqueProtegido
    template_name = "horario/base_horario.html"
    titulo = "Reserva Bloques protegidos Módulo"
    extra_context = {}

    def get_context_data(self, *args, **kwargs):

        context = super(ReservaBloqueProtegidoListView, self).get_context_data(*args, **kwargs)

        bloque = Bloque.objects.all().order_by("nombre")
        context['bloque'] = bloque

        return context

class ReservaBloqueProtegidoCreateView(StaffRequiredMixin, ViewCreateView):
    form_class = ReservaBloqueProtegidoForm
    template_name = "parametros/form.html"
    titulo = "Agrega Reserva de Bloque Protegido"
    success_message = "Se han reservado los bloques"
    success_url = "/reservabloqueprotegido/"

    def get_success_message(self, cleaned_data):
        #cleaned_data is the cleaned data from the form which is used for string formatting
        return self.success_message

class ReservaBloqueProtegidoUpdateView(StaffRequiredMixin, ViewUpdateView):
    model = ReservaBloqueProtegido
    form_class = ReservaBloqueProtegido
    template_name = "parametros/form.html"
    success_message = "Se han Actualizado los bloques"
    success_url = "/reservabloqueprotegido/"

    def get_success_message(self, cleaned_data):
        #cleaned_data is the cleaned data from the form which is used for string formatting
        return self.success_message

class ReservaBloqueProtegidoDeleteView(StaffRequiredMixin, ViewDeleteView):
    model = ReservaBloqueProtegido
    template_name = "parametros/elimina.html"
    success_message = 'Se han eliminado los bloques protegidos'
    success_url = "/reservabloqueprotegido/"

    def delete(self, request, *args, **kwargs):
        obj = self.get_object()
        messages.success(self.request, self.success_message %dict(nombre=obj,))
        return super(ViewDeleteView, self).delete(request, *args, **kwargs)

class CursosGrupoListView(StaffRequiredMixin, ViewListView):
    model = CursosGrupo
    template_name = "horario/base_horario.html"
    titulo = "Cursos Grupo"
    extra_context = {}

    def get_context_data(self, *args, **kwargs):

        context = super(CursosGrupoListView, self).get_context_data(*args, **kwargs)

        carrera = Carrera.objects.all()
        context["carrera"]  = carrera

        periodo = Periodo.objects.all()
        context["periodo"] = periodo

        return context

class CursosGrupoCreateView(StaffRequiredMixin, ViewCreateView):
    form_class = CursosGrupoForm
    template_name = "horario/cursos_grupo_table.html"
    titulo = "Agrega Modulos Compartidos"
    success_message = "Se agregado los módulos compartidos"
    success_url = "/cursosgrupo/"

    def get_success_message(self, cleaned_data):
        #cleaned_data is the cleaned data from the form which is used for string formatting
        return self.success_message

class CursosGrupoUpdateView(StaffRequiredMixin, ViewUpdateView):
    model = CursosGrupo
    form_class = CursosGrupo
    template_name = "horario/cursos_grupo_table.html"
    success_message = "Se han Actualizado los modulos compartidos"
    success_url = "/cursosgrupo/"

    def get_success_message(self, cleaned_data):
        #cleaned_data is the cleaned data from the form which is used for string formatting
        return self.success_message

class CursosGrupoDeleteView(StaffRequiredMixin, ViewDeleteView):
    model = CursosGrupo
    template_name = "parametros/elimina.html"
    success_message = 'Se han eliminado los modulos compartidos'
    success_url = "/cursosgrupo/"

    def delete(self, request, *args, **kwargs):
        obj = self.get_object()
        messages.success(self.request, self.success_message %dict(nombre=obj,))
        return super(ViewDeleteView, self).delete(request, *args, **kwargs)

class HorarioListView(StaffRequiredMixin, ViewListView):
    #queryset = Periodo.objects.all().order_by("-id")

    template_name = "horario/base_horario.html"
    titulo = "Listado de Horarios"

    def get_queryset(self):
        # return Periodo.objects.all().order_by("-id")
        query = PeriodoProfesorModulo.objects.all()
        query = query.distinct('carrera', 'periodo', 'plan')
        return query

class HorarioTemplateView(StaffRequiredMixin, TemplateView):
    #edit
    template_name = "horario/base_horario.html"

    def get_context_data(self, **kwargs):

        context = super(HorarioTemplateView, self).get_context_data(**kwargs)
        context["titulo"] = "Horario"

        periodo = self.request.GET.get("periodo")
        query = Periodo.objects.all().order_by("nombre")
        context["queryset_periodo"] = query

        carrera = self.request.GET.get("carrera")
        query = Carrera.objects.all().filter()
        context["queryset_carrera"] = query

        dia_semana = collections.OrderedDict(sorted(dic_dia_semana.items()))
        context["dia_semana"] = dia_semana

        cg = create_dic_cursos_grupo(periodo)
        context["cursos_grupo"] = cg

        query = PeriodoProfesorModulo.objects.all()
        if periodo is not None:
            query = query.filter(periodo__id=periodo)
        if carrera is not None:
            query = query.filter(carrera__id=carrera)
        query = query.order_by("modulo__semestre__nombre")

        dic_ppm = {}
        for ppm in query:

            dic=create_dic_bloque()
            dic_temp = dic

            h = Horario.objects.all()
            h = h.filter(periodoprofesormodulo=ppm, reservado=True)
            h = h.order_by("dia_semana",
                    "periodoprofesormodulo__modulo__semestre__nombre",
                    "periodoprofesormodulo__profesor__nombre",
                    )

            for x in h:
                temp = dic_temp[x.dia_semana]
                xx = temp[x.bloque] = x.actividad.identificador

            #actualizo diccionario,
            #agrego como key a ppm para los valores de dic
            dic_ppm[ppm] = dic
            """
            Estructura del nuevo diccionario
            {ppm:
                {'1':
                    {bloque:identificador}
                }
            }
            """
        context["horario"] = dic_ppm

        context = create_dic_bloque_title(context)
        return context

@csrf_exempt
def HorarioSave(request):

    if request.method == "POST" and request.is_ajax():
        model = Horario
        dic = request.POST.get("diccionario")
        dic = json.loads(dic)
        valor = request.POST.get("valor") #ultimo valor insertado
        bloque1 = dic["accion bloque1"]
        bloque2 = dic["accion bloque2"]
        bloque3 = dic["accion bloque3"]
        bloque4 = dic["accion bloque4"]
        bloque5 = dic["accion bloque5"]
        bloque6 = dic["accion bloque6"]
        bloque7 = dic["accion bloque7"]
        bloque8 = dic["accion bloque8"]
        bloque9 = dic["accion bloque9"]
        bloque10 = dic["accion bloque10"]

        profesor = dic["profesor"];
        modulo = dic["modulo"]
        plan = dic["plan"]
        semestre = dic["semestre"]
        dia_semana = dic["dia_semana"]
        titulo_bloque = dic["titulo_bloque"]

        query_ppm = PeriodoProfesorModulo.objects.all().filter(
                profesor__nombre=profesor,
                modulo__nombre=modulo,
                modulo__plan__nombre = plan,
                )

        query_horario = Horario.objects.all()
        query_horario_ppm = query_horario.filter(periodoprofesormodulo=query_ppm[0])

        validar, msj = valida_cantidad_horas(query_horario_ppm, valor)

        if validar is False:
            return HttpResponse(msj)

        validar1, msj = valida_choque_horario(dia_semana, titulo_bloque,
                query_ppm[0].periodo,
                query_ppm[0].modulo.semestre,
                valor,
                )
        if validar1 is False:
            return HttpResponse(msj)

        if validar and validar1:
            # if valida:
            #     if validar1:
            #         msj = msj1
            query_horario = query_horario_ppm.filter(dia_semana=dia_semana)
            if query_horario.exists():
                print("existe")
                query_horario=query_horario.get()
                query_horario.bloque1=bloque1
                query_horario.bloque2=bloque2
                query_horario.bloque3=bloque3
                query_horario.bloque4=bloque4
                query_horario.bloque5=bloque5
                query_horario.bloque6=bloque6
                query_horario.bloque7=bloque7
                query_horario.bloque8=bloque8
                query_horario.bloque9=bloque9
                query_horario.bloque10=bloque10
                # query_horario.dia_semana=dia_semana
            else:
                print("no existe")
                query_horario=Horario(
                        periodoprofesormodulo=query_ppm[0],
                        bloque1=bloque1,
                        bloque2=bloque2,
                        bloque3=bloque3,
                        bloque4=bloque4,
                        bloque5=bloque5,
                        bloque6=bloque6,
                        bloque7=bloque7,
                        bloque8=bloque8,
                        bloque9=bloque9,
                        bloque10=bloque10,
                        dia_semana = dia_semana,
                        )
                query_horario.save()
            return HttpResponse(msj)
        else:

            return HttpResponse(msj)
        #return redirect("/horario/add/")

    else:
        return redirect("/horario/add/")

@csrf_exempt
def GetPlan(request):

    if request.method == "POST" and request.is_ajax():
        codigo = request.POST.get("codigo")
        query = Plan.objects.all().filter(carrera__id=codigo)
        query = query.order_by("-id")

        return JsonResponse(serializers.serialize('json', query), safe=False)

@csrf_exempt
def GetPeriodo(request):

    if request.method == "POST" and request.is_ajax():
        #codigo = request.POST.get("codigo")
        query = Periodo.objects.all().order_by("nombre")

        return JsonResponse(serializers.serialize('json', query), safe=False)

@csrf_exempt
def GetProfesor(request):

    if request.method == "POST" and request.is_ajax():
        #codigo = request.POST.get("codigo")
        query = Profesor.objects.all().order_by("-id")

        return JsonResponse(serializers.serialize('json', query), safe=False)

@csrf_exempt
def GetModulo(request):

    if request.method == "POST" and request.is_ajax():
        #plan #FIXME
        codigo = request.POST.get("codigo")
        p = request.POST.get("periodo")
        if codigo != "":
            cg = CursosGrupo.objects.values_list("curso_grupo").filter(periodo_id=p)
        e = ModuloEspejo.objects.values_list("espejo")
        query = Modulo.objects.all().filter(plan__id = codigo)
        query = query.exclude(id__in=e)
        query = query.exclude(id__in=cg)
        query = query.order_by("-id")

        return JsonResponse(serializers.serialize('json', query), safe=False)

@csrf_exempt
def GetCarrera(request):

    if request.method == "POST" and request.is_ajax():
        #codigo = request.POST.get("codigo")
        query = Carrera.objects.all()
        query = query.order_by("nombre")

        return JsonResponse(serializers.serialize('json', query), safe=False)

@csrf_exempt
def GetActividad(request):

    if request.method == "POST" and request.is_ajax():
        codigo = request.POST.get("codigo")
        query = Actividad.objects.all()
        query = query.order_by("nombre")

        return JsonResponse(serializers.serialize('json', query), safe=False)

@csrf_exempt
def GetValidaPpm(request):
    """
    Método que ejecuta un query con los datos de PeriodoProfesorModulo y retorna
    si existe o no el nuevo objecto en la clase
    Requiere los campos:
        * Periodo
        * Carrera
        * Plan
        * Modulo
        * Profesor
    """

    if request.method == "POST" and request.is_ajax():
        periodo = request.POST.get("periodo")
        carrera = request.POST.get("carrera")
        plan = request.POST.get("plan")
        modulo = request.POST.get("modulo")
        profesor = request.POST.get("profesor")

        query = PeriodoProfesorModulo.objects.all()
        query = query.filter(
                periodo__id = periodo,
                carrera__id = carrera,
                plan__id = plan,
                modulo__id = modulo,
                profesor__id = profesor,
                )

        if query.exists():
            msj = "El profesor %(profesor)s ya fue agendado con el modulo "
            msj +="%(modulo)s en la carrera %(carrera)s para el periodo %(periodo)s"
            msj = msj %{"profesor":query[0].profesor.nombre,
                    "modulo": query[0].modulo.nombre,
                    "carrera": query[0].carrera.nombre,
                    "periodo": query[0].periodo.nombre
                    }
            dic={"success": False,
                    "msj":msj}
        else:
            dic={"success": True,
                    "msj":""}

            dic = json.dumps(dic).encode('utf_8')

        return HttpResponse(dic)

# para salvar actividad en cierto bloque
@csrf_exempt
def SaveActividadBloque(request):

    if request.method == "POST" and request.is_ajax():
        codigo = request.POST.get("codigo")
        s = Horario.objects.all()
        # query = query.order_by("nombre")

        s = s.filter(dia = dia_semana)
        s = s.filter(bloque = bloque)
        s = s.filter(ppm = periodoprofesormodulo)

        s.save()
        s.update()

    return HttpResponse("")

@csrf_exempt
def SaveHorarioProtegido(request):

    if request.method == "POST" and request.is_ajax():
        bloque = request.POST.get("bloque")
        value = request.POST.get("value")

        b = Bloque.objects.all()
        b = b.filter(nombre=bloque)

        r = ReservaBloqueProtegido.objects.all()
        r = r.filter(bloque = b[0])

        if value == "X":
            value = True
        else:
            value = False

        if not r.exists():
            r = r(
                    bloque = b[0],
                    reservado = value,
                    )
            r.save()
        else:
            r.update(
                    reservado = value
                    )

            return HttpResponse("")

@csrf_exempt
def saveHorario(request):
    """
    POST trae como valores:
    row = Fila que refiere al día de la semana.
    col = Columna que referencia al bloque.
    value = Valor de texto de la celda clickeada.
    periodo = Valor del combo periodo
    carrera = Valor del combo carrera
    plan = Valor del combo plan
    modulo = Valor del combo modulo
    profesor = Valor del combo de profesor
    """
    if request.method == "POST" and request.is_ajax():

        #FIXME
        actividad = request.POST.get("value")
        dia = request.POST.get("row")
        bloque = request.POST.get("bloque")

        #datos de periodo prof modulo
        periodo = request.POST.get("periodo")
        carrera = request.POST.get("carrera")
        plan = request.POST.get("plan")
        modulo = request.POST.get("modulo")
        profesor = request.POST.get("profesor")

        block = Bloque.objects.all()
        #num = block.filter(id = bloque)
        block = block.filter(nombre = bloque)

        if actividad != "":
            actividad_query = Actividad.objects.all()
            actividad_query = actividad_query.filter(identificador = actividad)
            actividad=actividad_query[0]

            #valida si existe el mismo profesor en bloque seleccionado
            #para otro modulo
            v, msj = valida_choque_horario_profesor(periodo,
                    modulo,
                    profesor,
                    dia,
                    bloque,
                    carrera,
                    )
            if (not v):
                return HttpResponse(msj)

            v, msj = valida_choque_horario_modulo_semestre(block[0],
                    dia,
                    plan,
                    profesor,
                    )
            if (not v):
                return HttpResponse(msj)

        else:
            actividad = None

        #query de PPM a fin de actualizar horario, se obtiene un solo resultado
        query = PeriodoProfesorModulo.objects.all()
        query = query.filter(periodo__id = periodo)
        query = query.filter(carrera__id = carrera)
        query = query.filter(plan__id = plan)
        query = query.filter(modulo__id = modulo)
        query = query.filter(profesor__id = profesor)

        print("periodo: ", periodo)
        print("carrera: ", carrera)
        print("plan: ", plan)
        print("modulo: ", modulo)
        print("profesor ", profesor)
        print(query)

        #Si el query existe, quiere decir que esta actualizando un dato
        if query.exists():

            h = Horario.objects.all()
            h = h.filter(periodoprofesormodulo = query[0])

            #valido la cantidad de horas para la actividad
            v,msj = valida_cantidad_horas(actividad, query=h,
                    modulo_id=modulo, nuevo=False)

            if (not v):
                return HttpResponse(msj)

            #Filtro para chequear si en horario ya está reservado el bloque
            a = h.filter(dia_semana = dia, bloque = block[0])

            #Se actualiza un bloque de horario ya establecido
            if a.exists():
                a = a.get()
                #Si la actividad es texto blanco se cambia a reservado False
                if actividad is None:
                    a.reservado = False
                else:
                    a.reservado = True

                a.actividad = actividad
                a.save()
            else:
                a = Horario(periodoprofesormodulo = query[0],
                        dia_semana = dia,
                        reservado = True,
                        bloque = block[0],
                        actividad = actividad,
                        )
                a.save()
        else:
            #no existe está creando
            c = Carrera.objects.all()
            c = c.filter(id = carrera)

            p = Profesor.objects.all()
            p = p.filter(id = profesor)

            m = Modulo.objects.all()
            m = m.filter(id = modulo)

            h = HorarioTemp.objects.all()
            h = h.filter(carrera = c[0],
                    profesor = p[0],
                    modulo = m[0],
                    )

            #valido la cantidad de horas para la actividad
            v,msj = valida_cantidad_horas(actividad, query=h,
                    modulo_id=modulo,nuevo=False)

            if (not v):
                return HttpResponse(msj)

            a = h.filter(dia_semana = dia,
                    bloque = block[0]
                    )

            if a.exists():
                #Si la actividad es None, se debe eliminar el registro temporal
                if actividad is None:
                    a.delete()
                else:
                    a = a.get()
                    a.actividad = actividad
                    a.save()
            else:
                a = HorarioTemp(
                        dia_semana = dia,
                        reservado = True,
                        bloque = block[0],
                        actividad = actividad,
                        carrera = c[0],
                        profesor = p[0],
                        modulo = m[0],
                        )
                a.save()

    return HttpResponse(None)

@csrf_exempt
def deleteHorarioTemp(request):
    """
    Utilitario para eliminar objetos temporales de la clase HorarioTemp

    POST Trae valores:
        * carrera
        * modulo
        * profesor
    """
    if request.method == "POST" and request.is_ajax():
        #datos del formulario PPM
        carrera = request.POST.get("carrera")
        modulo = request.POST.get("modulo")
        profesor = request.POST.get("profesor")

        h = HorarioTemp.objects.all()
        h = h.filter(carrera__id = carrera,
                modulo__id = modulo,
                profesor__id = profesor,
                )
        h.delete()

    return HttpResponse(None)

@csrf_exempt
def saveCursosGrupo(request):

    if request.method == "POST" and request.is_ajax():
        #cursosgrupo
        cursosgrupo = request.POST.get("cursosgrupo")
        if cursosgrupo == "":
            return HttpResponse(None)

        #Datos de PPM
        periodo = request.POST.get("periodo")
        carrera = request.POST.get("carrera")
        plan = request.POST.get("plan")
        modulo = request.POST.get("modulo")
        profesor = request.POST.get("profesor")

        ppm = PeriodoProfesorModulo.objects.all()
        ppm = ppm.filter(periodo__id = periodo,
                carrera__id = carrera,
                plan__id = plan,
                modulo__id = modulo,
                profesor__id = profesor
                )

        cg = Modulo.objects.all().filter(id=cursosgrupo)

        if ppm.exists():
            v, msj = valida_existe_grupos_cursos(cg[0], ppm[0])
            if not v:
                return HttpResponse(msj)
            cg = CursosGrupo(periodoprofesormodulo = ppm[0],
                    modulo=cg[0])
            cg.save()

    return HttpResponse(None)

@csrf_exempt
def GetModuloEspejoGruposCurso(request):

    if request.method == "POST" and request.is_ajax():
        #get modulo id
        modulo = request.POST.get("modulo")

        if modulo == "":
            return HttpResponse(None)

        e = ModuloEspejo.objects.all().filter(modulo__id=modulo)

        cg = CursosGrupo.objects.all().filter(modulo__id=modulo)

        msj = ""
        table = ""

        if e.exists():
            msj = "%s tiene asociado lo siguiente:\n\n"%e[0].modulo.nombre
            msj += "Módulo Espejo:\n"
            for i in e:
                msj +="\t \t * %s "%i.espejo.nombre
                msj += "del plan %s "%i.espejo.plan.nombre
                msj += "de %s"%i.espejo.carrera.nombre

                #FIXME
                table +="<tr>"
                table +="<td name=id hidden>%s</td>"%i.id
                table +="<td width=30%%> %s </td>"%i.espejo.carrera.nombre
                table +="<td width=30%%>%s</td>"%i.espejo.plan.nombre
                table +="<td width=30%%>%s</td>"%i.espejo.nombre
                table +="""<td>
                <center>
                    <button class='btn btn-danger btn-sm delete-cursos-grupo'>
                    <span class='glyphicon glyphicon-minus'></span></button>
                    </center>
                </td>
                """

                table +="</tr>"

        if cg.exists():
            if msj == "":
                msj = "%s tiene asociado lo siguiente:"%e[0].modulo.nombre
            msj += "\n\n"
            msj += "Grupos Curso:\n"

            for i in cg:
                msj +="\t \t * %s "%i.curso_grupo.nombre
                msj += "del plan %s "%i.curso_grupo.plan.nombre
                msj += "de %s"%i.curso_grupo.carrera.nombre

        if msj != "":
            dic={"success": False,
                    "msj":msj,
                    "table":table}
        else:
            dic={"success": True,
                    "msj":"",
                    "table":table}

        dic = json.dumps(dic).encode('utf_8')

        return HttpResponse(dic)


""" This modules enables to calculate and plot the estimated degradation of a lithium ion battery, over its operations
defined a file located in the folder input_data"""

import os
import pandas as pd
import matplotlib.pyplot as plt
import time

from degradation_model.degradation_model import final_degradation_model, nonlinear_general_model

colors = ['red', 'blue', 'green', 'orange', 'purple', 'black', 'grey', 'brown']

def nearest(items, pivot):
    return min(items, key=lambda x: abs(x - pivot))

def even_selection_array(n, array_in):
    step = (len(array_in) - 1) / (n - 1)
    array_out = []
    for i in range(0, n):
        array_out.append(array_in[round(step * i)])
    return array_out

def convert_vector_time(time_array):
    array_out = []
    for i in range(0, len(time_array)):
        diff = time_array.iloc[i] - time_array.iloc[0]
        array_out.append(diff.total_seconds())
    return array_out

time1 = time.time()

fig = plt.figure(figsize=(5, 4), dpi=100)
ax1 = fig.add_subplot(111)

temperature = 21
chemistry = 'NMC'
alpha_sei = 5.87e-02
beta_sei = 1.06e+02

for m, fn in enumerate(os.listdir('input_data/')):
    if os.path.isfile(os.path.join('input_data/', str(fn))):
        filename, file_extension = os.path.splitext(fn)
        if file_extension == '.csv':
            # file processing
            df = pd.read_csv('input_data/' + fn, parse_dates=[0])
            dtm = df.iloc[:, 0]  # date time
            soc = df.iloc[:, 1]  # state of charge

            # calculation of total duration
            last_index = dtm.index[-1]
            first_time = dtm[1]
            last_time = dtm[last_index]
            diff = last_time - first_time
            total_duration = diff.total_seconds()

            time_linspace = even_selection_array(365, dtm)  # selection 100 time points from dtm

            cal_results = [0]
            cyc_results = [0]
            linearised_deg_v = [0]
            nonlinear_deg_v = [0]
            time_index_v = [0]

            for k in range(1, len(time_linspace)):

                # searches in dtm the index at which the date is equal to time_linspace[i]
                index_dtm_i = dtm[dtm == time_linspace[k]].index.tolist()[0]
                time_index_v.append(index_dtm_i)

                # extracts the relevant time data
                time_v = dtm.iloc[time_index_v[k-1]:time_index_v[k]]
                # and converts them to time difference
                time_v = convert_vector_time(time_v)

                # extracts the relevant soc data
                soc_v = soc.iloc[time_index_v[k-1]:time_index_v[k]].as_matrix()

                # calculate calendar and cycling degradation
                cal_deg, cyc_deg = final_degradation_model(time_v=time_v,
                                                           soc_v=soc_v,
                                                           T=temperature,
                                                           time=time_v[-1],
                                                           chemistry=chemistry,
                                                           delta=0.1,
                                                           title='DST')

                # stores the results
                cal_results.append(cal_results[k-1] + cal_deg)
                cyc_results.append(cyc_results[k-1] + cyc_deg)

                linearised_deg = cal_results[k]+cyc_results[k]
                linearised_deg_v.append(linearised_deg)

                non_linear_deg = nonlinear_general_model(alpha_sei, beta_sei, linearised_deg)

                nonlinear_deg_v.append(non_linear_deg)

            remaining_capa = []

            for i in range(0, len(nonlinear_deg_v)):
                remaining_capa.append(100*(1-nonlinear_deg_v[i]))

            ax1.plot(time_linspace, remaining_capa, 'x-', color=colors[m], label=filename)
            ax1.set_xlabel('Time')
            ax1.set_ylabel('Remaining capacity [%]')
            ax1.set_ylim([80, 100])

            plt.legend()
            plt.tight_layout()
            plt.draw()
plt.show()


import os
import time
from collections import defaultdict, Counter

import pytest

day = os.path.basename(__file__).split(".")[0]

def parse(file: str):
    graph = defaultdict(set)
    for n1, n2 in [cave.split("-") for cave in open(file).read().split("\n")]:
        if n1 != "end" and n2 != "start":
            graph[n1].add(n2)
        if n1 != "start" and n2 != "end":
            graph[n2].add(n1)
    return graph

def dfs(src: str, dst: str, graph: dict, paths: list, path: list = None, allow_twice=False):
    if path is None:
        path = [src]

    if src == dst:
        paths.append(path)
    else:
        for adjacent in graph[src]:
            twice = 2 not in Counter([cave for cave in path if cave.islower()]).values() if allow_twice else False
            if adjacent.isupper() or twice or adjacent not in path:
                path.append(adjacent)
                dfs(adjacent, dst, graph, paths, path, allow_twice=allow_twice)
                path.pop()

def p1(graph):
    paths = []
    dfs("start", "end", graph, paths)
    return len(paths)

def p2(graph):
    paths = []
    dfs("start", "end", graph, paths, allow_twice=True)
    return len(paths)

cases_p1 = [(f"inputs/{day}.input.test", 10), (f"inputs/{day}.input.test2", 19), (f"inputs/{day}.input.test3", 226)]
cases_p2 = [(f"inputs/{day}.input.test", 36), (f"inputs/{day}.input.test2", 103), (f"inputs/{day}.input.test3", 3509)]

@pytest.mark.parametrize("case", cases_p1)
def test_p1(case):
    file, paths = case
    assert p1(parse(file)) == paths

@pytest.mark.parametrize("case", cases_p2)
def test_p2(case):
    file, paths = case
    assert p2(parse(file)) == paths

def main():
    input_file = f'inputs/{day}.input'

    t0 = time.perf_counter()
    print(
        f"P1: "
        f"{p1(parse(input_file))} "
        f"{(time.perf_counter() - t0) * 1000:.2f} ms"
    )

    t0 = time.perf_counter()
    print(
        f"P2: "
        f"{p2(parse(input_file))} "
        f"{(time.perf_counter() - t0) * 1000:.2f} ms"
    )

if __name__ == "__main__":
    main()


import asyncio
import discord
from discord.ext import commands, tasks

f_ = open("config.txt", "r")
f = f_.read()
f_.close()

config = {}

f = f.splitlines()

for a in f:
    values = a.split("=")
    config[values[0]] = values[1]

ffmpeg_options = {
    'options': '-vn'
}

bot = commands.Bot(command_prefix=commands.when_mentioned, description='play a sound in a voice channel controlled by a reaction')
bot.remove_command("help")
bot.channel = int(config["channel"])
bot.message = int(config["message"])
bot.emoji = int(config["emoji"])
bot.file = config["file"]

@bot.event
async def on_ready():
    ch = bot.get_channel(bot.channel)

    try:
        m = await ch.fetch_message(bot.message)
        e = bot.get_emoji(bot.emoji)
        await m.add_reaction(e)
        print(f"""Ready as {bot.user} with these options:

• Channel: {ch.name}
• Message: {str(m.content)[:15]}...
• Emoji: {e.name}
• File: {bot.file}

You can invite me to your server with this link: {discord.utils.oauth_url(bot.user.id, permissions = discord.Permissions(permissions = 8))}
""")
    except:
        print(f"""Ready as {bot.user}:

You can invite me to your server with this link: {discord.utils.oauth_url(bot.user.id, permissions = discord.Permissions(permissions = 8))}
""")

@bot.event
async def on_raw_reaction_add(payload):
    ch = bot.get_channel(bot.channel)
    msg = await ch.fetch_message(bot.message)
    if payload.message_id == bot.message:
        if payload.emoji.id == bot.emoji:
            try:
                ctx = await bot.get_context(msg)
                member = ctx.guild.get_member(payload.user_id)

                if ctx.voice_client is None:
                    if member.voice:
                        await member.voice.channel.connect()
                    else:
                        if member == ctx.guild.me:
                            return
                        await msg.remove_reaction(bot.get_emoji(bot.emoji), member)
                        return

                query = bot.file

                v = ctx.voice_client

                source = discord.PCMVolumeTransformer(discord.FFmpegPCMAudio(query))
                v.play(source, after=lambda e: print('Player error: %s' % e) if e else None)

            except Exception as e:
                print(e)

@bot.event
async def on_raw_reaction_remove(payload):
    ch = bot.get_channel(bot.channel)
    msg = await ch.fetch_message(bot.message)
    if payload.user_id == bot.user.id:
        await msg.add_reaction(bot.get_emoji(bot.emoji))
        return
    if payload.message_id == bot.message:
        if payload.emoji.id == bot.emoji:
            ctx = await bot.get_context(msg)

            if ctx.voice_client is None:
                return

            await ctx.voice_client.disconnect()

bot.run(config["token"])


import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import sawtooth

from nerdart import Parser
from nerdart.utils import save_or_show

@save_or_show(__file__)
def plot(args):
    n_points = args.n_points
    n_waves = args.n_waves
    scale_factor = args.scale_factor
    tilt_factor = args.tilt_factor

    points = np.arange(n_points)
    x = points.copy()
    y = np.zeros(n_points)

    for point in points:
        xi = x + point * tilt_factor
        y[:] = point

        size = 0.5 * sawtooth(2 * np.pi * n_waves * (point / n_points), 0.5) + 0.5
        size *= scale_factor

        plt.scatter(xi, y, c="red", alpha=0.4, lw=0, s=size)
        plt.scatter(xi, y, c="blue", alpha=0.4, lw=0, s=scale_factor - size)

    if tilt_factor >= 0:
        plt.xlim(0, tilt_factor * n_points - tilt_factor + n_points - 1)
    else:
        plt.xlim(tilt_factor * n_points - tilt_factor, n_points - 1)
    plt.ylim(0, n_points - 1)
    plt.axis("off")

def main():
    parser = Parser()
    parser.add("-p", "--n-points", type=int, default=25)
    parser.add("-w", "--n-waves", type=int, default=3)
    parser.add("-s", "--scale-factor", type=float, default=500)
    parser.add("-t", "--tilt-factor", type=float, default=0)
    args = parser.parse()
    plot(args)

if __name__ == "__main__":
    main()


import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GL import shaders
import numpy as np

# Define the window dimensions
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600

# Vertex shader source code
vertex_shader_code = """
#version 120
attribute vec2 position;
void main()
{
    gl_Position = vec4(position, 0.0, 1.0);
}
"""

# Fragment shader source code for the Mandelbrot set
fragment_shader_code = """
#version 120
uniform vec2 resolution;
uniform int max_iterations;

void main()
{
    vec2 uv = (2.0 * gl_FragCoord.xy - resolution) / min(resolution.y, resolution.x);
    vec2 z = uv;
    int i;
    for (i = 0; i < max_iterations; i++)
    {
        if (length(z) > 2.0)
            break;
        z = vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y) + uv;
    }
    float color = float(i) / float(max_iterations);
    gl_FragColor = vec4(vec3(color), 1.0);
}
"""

def create_shader_program():
    # Create and compile the vertex shader
    vertex_shader = shaders.compileShader(vertex_shader_code, GL_VERTEX_SHADER)

    # Create and compile the fragment shader
    fragment_shader = shaders.compileShader(fragment_shader_code, GL_FRAGMENT_SHADER)

    # Link the shaders into a shader program
    shader_program = shaders.compileProgram(vertex_shader, fragment_shader)

    return shader_program

def main():
    pygame.init()
    pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), DOUBLEBUF | OPENGL)

    shader_program = create_shader_program()
    glUseProgram(shader_program)

    resolution_uniform = glGetUniformLocation(shader_program, "resolution")
    max_iterations_uniform = glGetUniformLocation(shader_program, "max_iterations")

    glUniform2f(resolution_uniform, WINDOW_WIDTH, WINDOW_HEIGHT)
    glUniform1i(
        max_iterations_uniform, 1000
    )  # Adjust the maximum number of iterations as needed

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        glClear(GL_COLOR_BUFFER_BIT)
        glBegin(GL_QUADS)
        glVertex2f(-1, -1)
        glVertex2f(1, -1)
        glVertex2f(1, 1)
        glVertex2f(-1, 1)
        glEnd()
        pygame.display.flip()

if __name__ == "__main__":
    main()


from collections import deque
    #HOW TO SOLVE ANY GRAPH PROBLEM:

#Translate the problem into graph terminology
    #What are the vertices, edges, weights (if needed)?

""""
Vertices: islands
Edges: 1's that are connected
Weights: None
"""""

""""
Plan
1. translate the problem into graph terminology
vertex - is a cell
edge - neighboring cells

2. Build your graph
it's the grid so need to build it!

3. traverse your graph/grid
go through each element in the grid
if we finda 1, increment num islands, then we want to traverse all of its
connected components and mark them as visited
return numIslands

"""""

#Build your graph
    #Do you even need to build a graph? Should you use an adjacency matrix/list?

#Traverse your graph
    #Should you use BFS/DFS? Do you need an auxiliary data structure? (list containing path?)

# Start at x, y and mark connected components that are 1 visited
def markConnectedComponentsAsVisited(grid, visited, x, y):
    width, height = len(grid[0], len(grid))
    stack = deque()
    stack.append((x,y))
    while len(stack) > 0:
        x, y = stack.pop()
        if visited[y][x]:
            continue
        visited[y][x] = True
        # Traverse all adjacent nodes that are also 1
        # Check left node
        if x - 1 >= 0 and grid[y][x - 1] == '1':
            stack.append((x - 1, y))
            # Check right node
        if x + 1 < width and grid[y][x + 1] == '1':
            stack.append((x + 1, y))
            # Check top node
        if y - 1 >= 0 and grid[y][x - 1] == '1':
            stack.append((x - 1, y))
            # Check bottom node
        if y + 1 < height and grid[y][x - 1] == '1':
            stack.append((x - 1, y))

def numIslands(grid):
    if len(grid) == 0:
        return 0
    width, height = len(grid[0]), len(grid)
    #visited[i][j] is True if cell in grid[i][j] has been visited
    visited = [[False] * width for x in range(height)]

    # double for loops
    # traverse through each
    for y in range(height):
        for x in range(width):
            if grid[y][x] == '1' and not visited[y][x]:
                numIslands += 1
                markConnectedComponentsAsVisited(grid, visited, x, y)
    return numIslands

input1 = [
    ["1", "1", "1", "1", "0"],
    ["1", "1", "0", "1", "0"],
    ["1", "1", "0", "0", "0"],
    ["0", "0", "0", "0", "0"]
]

input2 = [
    ["1", "1", "0", "0", "0"],
    ["1", "1", "0", "0", "0"],
    ["0", "0", "1", "0", "0"],
    ["0", "0", "0", "1", "0"]
]

print(numIslands(input1))


from flask import Flask, render_template, request
import json
import numpy as np
import pandas as pd
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
from sklearn.manifold import MDS
from sklearn.metrics import pairwise_distances
app = Flask(__name__)

class My_PCA:
    def __init__(self,csv_file,label_col):
        self.data_out=self.change_percent(self.remove_cat(csv_file))
        self.original_df,self.pca_components=self.compute_PCA(self.data_out)
        self.label,self.label_unique=self.get_data_label(csv_file,label_col)

    def get_data_label(self,csv_file,label_col):
        df_in = pd.read_csv(csv_file)
        # cat_list = ["City", "Rigorous Instruction Rating", "Collaborative Teachers Rating",
        #             "Supportive Environment Rating", "Effective School Leadership Rating",
        #             "Strong Family-Community Ties Rating","Trust Rating","Student Achievement Rating"]
        label=list(df_in[label_col])
        label_unique = list(np.unique(df_in[label_col]))
        return label,label_unique
    def remove_cat(self,csv_file):
        df_in = pd.read_csv(csv_file)
        cat_list = ["City", "Rigorous Instruction Rating", "Collaborative Teachers Rating",
                    "Supportive Environment Rating", "Effective School Leadership Rating",
                    "Strong Family-Community Ties Rating","Trust Rating","Student Achievement Rating"]
        df_out = df_in.drop(cat_list, axis=1)
        #del Average Proficiency.
        df_out=df_out.drop("Average Proficiency",axis=1)
        return df_out

    #transform percent to decimal.
    def change_percent(self,csv_data):
        percent_list = ["Percent ELL", "Student Attendance Rate", "Percent of Students Chronically Absent",
                    "Rigorous Instruction %", "Collaborative Teachers %","Supportive Environment %",
                    "Effective School Leadership %","Strong Family-Community Ties %","Trust %",]
        trans_func=lambda col: col.str.strip('%').astype(float)/100
        csv_data[percent_list]=csv_data[percent_list].apply(trans_func,axis=1)
        return csv_data

    def compute_PCA(self,df):
        StandScaler = StandardScaler()
        #no set n_components, it would save all components.
        pca = PCA(random_state=0)
        original_df = pca.fit_transform(StandScaler.fit_transform(df))
        # pca_percent = 100 * pca.explained_variance_ratio_
        # pca_cum_sum_var = np.cumsum(pca_percent)
        return original_df,pca.components_

class My_Scatter:
    def __init__(self,csv_file,x_var,y_var,label_col):
        self.x,self.y=self.get_data(csv_file,x_var,y_var)
        self.label=self.get_data_label(csv_file,label_col)
        self.x_name=x_var
        self.y_name=y_var

    #transform percent to decimal.
    def change_percent(self,csv_data):
        percent_list = ["Percent ELL", "Student Attendance Rate", "Percent of Students Chronically Absent",
                    "Rigorous Instruction %", "Collaborative Teachers %","Supportive Environment %",
                    "Effective School Leadership %","Strong Family-Community Ties %","Trust %",]
        trans_func=lambda col: col.str.strip('%').astype(float)/100
        csv_data[percent_list]=csv_data[percent_list].apply(trans_func,axis=1)
        return csv_data

    def get_data_label(self,csv_file,label_col):
        df_in = pd.read_csv(csv_file)
        label=list(df_in[label_col])
        return label

    def get_data(self,csv_file,x_var,y_var):
        df_in = pd.read_csv(csv_file)
        df_in=self.change_percent(df_in)
        x_data=list(df_in[x_var])
        y_data=list(df_in[y_var])
        return x_data,y_data

pca_class=My_PCA(csv_file='school_data_clean_v3.csv', label_col="City")
scatter_school_income=My_Scatter(csv_file='school_data_clean_v3.csv',
                                 x_var='School Income Estimate',y_var='Average Proficiency', label_col="City")
scatter_trust=My_Scatter(csv_file='school_data_clean_v3.csv',
                                 x_var='Economic Need Index',y_var='Percent of Students Chronically Absent', label_col="City")

df_ori = pd.read_csv('school_data_clean_v3.csv')
df_pcp = pca_class.change_percent(df_ori)
# pcp_columns = ["City", "Rigorous Instruction Rating", "Collaborative Teachers Rating", "Student Attendance Rate", "Student Achievement Rating",
#  "Average ELA Proficiency", "Average Math Proficiency"]

@app.route('/')
def index():
    # return 'Hello World!'
    return render_template("index.html")

@app.route("/plotTop2PCA", methods=['POST', 'GET'])
def plotTop2OriginalPCA():
    if request.method == 'POST':
        points_data = list(zip(pca_class.original_df[:, 0], pca_class.original_df[:, 1],pca_class.label))
        axis_data = list(zip(pca_class.pca_components[0, :], pca_class.pca_components[1, :]))
        return json.dumps([points_data, axis_data,pca_class.label_unique])

@app.route("/barchart", methods=['POST', 'GET'])
def barchart():
    if request.method == 'POST':
        city_hist = df_ori['City'].value_counts().to_dict()
        # print(city_hist)
        # city = []
        # num = []
        # for key, value in city_hist.items():
        #     city.append(key)
        #     num.append(value)
        # resp = dict(
        #     city=city,
        #     freq=num
        # )
        resp = []
        for key, value in city_hist.items():
            resp.append(dict(
                city=key,
                num=value))
        return json.dumps(resp)

@app.route('/pcp', methods=['POST', 'GET'])
def pcp():
    if request.method == 'POST':
        # print(request.form)
        # pcp_columns = list(request.form['pcp_columns'])
        # print(pcp_columns)
        resp = dict(
            # data = df_pcp.loc[:, pcp_columns].to_json(orient = "index"),
            # column_name = pcp_columns,
            data = df_pcp.to_json(orient = "index"),
            city = df_pcp.loc[:, 'City'].tolist()
        )
        return json.dumps(resp)

@app.route("/plotScatterSchoolIncome", methods=['POST', 'GET'])
def plotScatterSchoolIncomeFunc():
    if request.method == 'POST':
        points_data = list(zip(scatter_school_income.x, scatter_school_income.y,scatter_school_income.label))
        return json.dumps([points_data,scatter_school_income.x_name,scatter_school_income.y_name])

@app.route("/plotScatterTrust", methods=['POST', 'GET'])
def plotScatterTrustFunc():
    if request.method == 'POST':
        points_data = list(zip(scatter_trust.x, scatter_trust.y,scatter_trust.label))
        return json.dumps([points_data,scatter_trust.x_name,scatter_trust.y_name])

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=8080, debug=True)


import random
import string

from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.mail import BadHeaderError, send_mail
from django.http import HttpResponse
from django.shortcuts import redirect, render
from django.urls import reverse
from django.views import View
from django.views.generic import DetailView, ListView, TemplateView

from rest_framework import generics, permissions, status
from rest_framework.response import Response

from nablapps.qrTickets.serializers import QrTicketSerializer

from .forms import EmailForm, EventForm
from .models import QrEvent, QrTicket

class ScanTicketView(TemplateView):
    template_name = "qrTickets/scan.html"

def render_ticket(request, qr_event_id, qr_ticket_id):
    ticket_url = (
        "nabla.no/qrTickets/register/" + str(qr_event_id) + "/" + str(qr_ticket_id)
    )
    url_list = [ticket_url]
    context = {"ticket_url": ticket_url, "url_list": url_list}
    return render(request, "qrTickets/render.html", context)

class QrEventListView(PermissionRequiredMixin, ListView):
    permission_required = "qrTickets.generate_tickets"
    model = QrEvent
    template_name = "qrTickets/event_list.html"
    paginate_by = 100

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context

class CreateEventView(PermissionRequiredMixin, View):
    permission_required = "qrTickets.generate_tickets"

    def get(self, request):
        event_form = EventForm()
        context = {"event_form": event_form}
        return render(request, "qrTickets/create_event.html", context)

    def post(self, request):
        event_form = EventForm(request.POST)
        if event_form.is_valid():
            nabla_event = event_form.get_nabla_event()
            event_name = event_form.get_event_name()

            # Create qr event
            event = QrEvent.objects.create(name=event_name, nabla_event=nabla_event)
            event.save()
        return redirect(reverse("qr-event-list"))

class EventDetailView(PermissionRequiredMixin, DetailView):
    permission_required = "qrTickets.generate_tickets"

    def get(self, request, pk):
        email_form = EmailForm()
        context = {"email_form": email_form}
        qr_event = QrEvent.objects.get(pk=pk)
        context["event"] = qr_event
        context["email_list"] = qr_event.ticket_set.all()
        return render(request, "qrTickets/qr_event_detail.html", context)

    def post(self, request, pk):
        qr_event = QrEvent.objects.get(pk=pk)
        email_list = []
        if qr_event.nabla_event:
            email_list += qr_event.nabla_event.users_attending_emails()
        email_form = EmailForm(request.POST)
        if email_form.is_valid():
            emails = email_form.get_emails()
            email_list += emails.splitlines()
        already_recieved_list = [
            ticket.__str__() for ticket in qr_event.ticket_set.all()
        ]
        for email in email_list:
            if email not in already_recieved_list:
                randstr = "".join(
                    random.SystemRandom().choice(string.ascii_uppercase + string.digits)
                    for _ in range(11)
                )
                ticket = QrTicket.objects.create(event=qr_event, email=email)
                ticket.ticket_id = str(ticket.id) + randstr
                ticket.save()

                subject = "din nablabillett"  # noe mer spes etterhvert
                message = "Din billett til " + str(ticket.event) + " finner du her:\n"
                link = (
                    "nabla.no/qrTickets/render/"
                    + str(qr_event.id)
                    + "/"
                    + ticket.ticket_id
                )
                message += link

                try:
                    send_mail(
                        subject,
                        message,
                        "noreply@nablatickets.no",
                        [email],
                        fail_silently=False,
                    )
                except BadHeaderError:
                    return HttpResponse("Invalid header found")
        return redirect(reverse("qr-event-detail", kwargs={"pk": pk}))

class RegisterTicketsView(PermissionRequiredMixin, View):
    permission_required = "qrTickets.register_tickets"

    def get(self, request, qr_event_id, qr_ticket_id):
        context = {
            "event_id": qr_event_id,
            "ticket_id": qr_ticket_id,
        }
        return render(request, "qrTickets/register.html", context)

    def post(self, request, qr_event_id, qr_ticket_id):
        qr_event = QrEvent.objects.get(pk=qr_event_id)
        try:
            qr_ticket = qr_event.ticket_set.get(ticket_id=qr_ticket_id)
            if qr_ticket.registered:
                return HttpResponse("Allerede registrert. Billetten er oppbrukt.")
            qr_ticket.register()
            qr_ticket.save()
        except QrTicket.DoesNotExist:
            return HttpResponse("Ikke en gyldig billett!")
        return HttpResponse("Billett registrert!")

class UpdateTicketsView(generics.UpdateAPIView):
    """
    API endpoint that allows tickets to be updated.
    """

    queryset = QrTicket.objects.all()
    serializer_class = QrTicketSerializer
    lookup_field = "ticket_id"
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

    def put(self, request, ticket_id):
        try:
            ticket = QrTicket.objects.get(ticket_id=ticket_id)
        except QrTicket.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
        serializer = QrTicketSerializer(ticket, data=request.data)
        if ticket.registered:
            return Response(status=status.HTTP_208_ALREADY_REPORTED)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


from django.shortcuts import render, get_object_or_404, HttpResponse, redirect
from django import forms
from django.forms import ModelForm
from .models import HostName, HostFather, HostMother, Contact, Additional

# =============== Forms =================

class HostNameForm(ModelForm):
    class Meta:
        model = HostName
        exclude = ['id']

class HostFatherForm(ModelForm):
    class Meta:
        model = HostFather
        exclude = ['id']

class HostMotherForm(ModelForm):
    class Meta:
        model = HostMother
        exclude = ['id']

class ContactForm(ModelForm):
    class Meta:
        model = Contact
        exclude = ['id']

class AdditionalForm(ModelForm):
    class Meta:
        model = Additional
        exclude = ['id']

class ConfirmForm(forms.Form):
    CONFIRM_CHOICES = (
        ('yes', 'Yes'),
        ('no', 'No'),
    )

    confirm = forms.ChoiceField(choices=CONFIRM_CHOICES, widget=forms.RadioSelect())

# ============== Home ===================

def home(request, template_name='host_family/home.html'):
    hostname = HostName.objects.all()
    hostfather = HostFather.objects.all()
    hostmather = HostMother.objects.all()
    contact = Contact.objects.all()
    additional = Additional.objects.all()
    # father_name = hostfather.firstname
    return render(request, template_name, {'host_list': hostname, 'hostfather': hostfather})

# ============== CRUD ===================

def new_host(request, template_name='host_family/host_form.html'):
    if request.method == 'POST':
        form1 = HostNameForm(request.POST)
        form2 = HostFatherForm(request.POST)
        form3 = HostMotherForm(request.POST)
        form4 = ContactForm(request.POST)
        form5 = AdditionalForm(request.POST)

        if all((form1.is_valid(), form2.is_valid(), form3.is_valid(), form4.is_valid(), form5.is_valid())):
            post1 = form1.save()
            post2 = form2.save(commit=False)
            post3 = form3.save(commit=False)
            post4 = form4.save(commit=False)
            post5 = form5.save(commit=False)
            post2.id = post1
            post3.id = post1
            post4.id = post1
            post5.id = post1
            post2.save()
            post3.save()
            post4.save()
            post5.save()
        else:
            return HttpResponse('wrong')

    else:
        form1 = HostNameForm()
        form2 = HostFatherForm()
        form3 = HostMotherForm()
        form4 = ContactForm()
        form5 = AdditionalForm()

    return render(request, template_name, {'form1': form1, 'form2': form2, 'form3': form3,\
                                           'form4': form4, 'form5': form5})

def detail_host(request, pk, template_name='host_family/host_detail.html'):
    host = get_object_or_404(HostName, pk=pk)
    father = get_object_or_404(HostFather, pk=pk)
    mother = get_object_or_404(HostMother, pk=pk)
    contact = get_object_or_404(Contact, pk=pk)
    additional = get_object_or_404(Additional, pk=pk)
    father_name = father.firstname
    return render(request, template_name, {'host': host, 'father': father, 'mother': mother,
                                           'contact': contact, 'additional': additional,
                                            'father_name': father_name})

def update_host(request, pk, template_name='host_family/host_form.html'):
    host = get_object_or_404(HostName, pk=pk)
    father = get_object_or_404(HostFather, pk=pk)
    mother = get_object_or_404(HostMother, pk=pk)
    contact = get_object_or_404(Contact, pk=pk)
    additional = get_object_or_404(Additional, pk=pk)

    if request.method == 'POST':
        form1 = HostNameForm(request.POST, instance=host)
        form2 = HostFatherForm(request.POST, instance=father)
        form3 = HostMotherForm(request.POST, instance=mother)
        form4 = ContactForm(request.POST, instance=contact)
        form5 = AdditionalForm(request.POST, instance=additional)
        if all((form1.is_valid(), form2.is_valid(), form3.is_valid(), form4.is_valid(), form5.is_valid())):
            post1 = form1.save()
            post2 = form2.save(commit=False)
            post3 = form3.save(commit=False)
            post4 = form4.save(commit=False)
            post5 = form5.save(commit=False)
            post2.id = post1
            post3.id = post1
            post4.id = post1
            post5.id = post1
            post2.save()
            post3.save()
            post4.save()
            post5.save()
            return redirect('host_list')
    else:
        form1 = HostNameForm(instance=host)
        form2 = HostFatherForm(instance=father)
        form3 = HostMotherForm(instance=mother)
        form4 = ContactForm(instance=contact)
        form5 = AdditionalForm(instance=additional)
    return render(request, template_name, {'form1': form1, 'form2': form2, 'form3': form3,
                                           'form4': form4, 'form5': form5})

def delete_host(request, pk, template_name='delete_confirm.html'):
    host = get_object_or_404(HostName, pk=pk)
    if request.method == 'POST':
        if request.POST['choice'] == 'yes':
            host.delete()
            return redirect('host_list')
        else:
            return HttpResponse('Fail')

    else:
        form = ConfirmForm()
    return render(request, template_name, {'form': form})


import xlwings as xw

# Khởi tạo file excel bằng modul App
app = xw.App(visible=True, add_book=False) # code này gán modul App với cái tên là app

# Tạo ra file excel mới gán tên là wb_new
wb = app.books.open('movies_1.xls')  #('movies_1.xls')
# wb_new = app.books.add()

# lưu file mới đến thư mục "D:\ThanhVu\code\python\Data_Science\"
wb.save(r'D:\ThanhVu\code\python\MyBook\Python_Excel\objSheet.xls')

# Đoạn code này đóng file excel mới toanh đó
wb.close()

# Đoạn code này tắt đối tượng app
app.quit()


from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import argparse
import json
import logging
import math
import os
import random
import time

import ipdb
import numpy as np
import torch
import torch.nn as nn
import wandb
from pysot.core.config import cfg
# === 這裡選擇要老師 or 亭儀的裁切出來的資料集 ===
from pysot.datasets.pcbdataset_new import PCBDataset
from pysot.models.model_builder import ModelBuilder
from pysot.tracker.tracker_builder import build_tracker
from pysot.utils.average_meter import AverageMeter
from pysot.utils.check_image import create_dir
from pysot.utils.distributed import (DistModule, average_reduce, dist_init,
                                     get_rank, get_world_size,
                                     reduce_gradients)
from pysot.utils.log_helper import add_file_handler, init_log, print_speed
from pysot.utils.lr_scheduler import build_lr_scheduler
from pysot.utils.misc import commit, describe
from pysot.utils.model_load import load_pretrain, restore_from
from tensorboardX import SummaryWriter
from torch.nn.utils import clip_grad_norm_
from torch.utils.data import DataLoader, Subset
from torch.utils.data.distributed import DistributedSampler

from tools.eval_pcb import evaluate

logger = logging.getLogger('global')
parser = argparse.ArgumentParser(description='siamrpn tracking')
parser.add_argument('--crop_method', type=str, help='teachr / amy')
parser.add_argument('--bg', type=str, nargs='?', const='', help='background')
parser.add_argument('--neg', type=float, help='negative sample ratio')
parser.add_argument('--anchors', type=int, help='number of anchors')
parser.add_argument('--epoch', type=int, help='epoch')
parser.add_argument('--batch_size', type=int, help='batch size')
parser.add_argument('--accum_iter', type=int, help='gradient accumulation iter')
parser.add_argument('--dataset_path', type=str, help='training dataset path')
parser.add_argument('--dataset_name', type=str, help='training dataset name')
parser.add_argument('--criteria', type=str, help='sample criteria for dataset')
parser.add_argument('--bk', type=str, help='whether use pretrained backbone')
parser.add_argument('--cfg', type=str, default='config.yaml', help='configuration of tracking')
parser.add_argument('--test_dataset', type=str, help='testing dataset path')
parser.add_argument('--seed', type=int, default=123456, help='random seed')
parser.add_argument('--local_rank', type=int, default=0, help='compulsory for pytorch launcer')
args = parser.parse_args()

def seed_torch(seed=0):
    random.seed(seed)
    os.environ['PYTHONHASHSEED'] = str(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)
    torch.backends.cudnn.benchmark = False
    torch.backends.cudnn.deterministic = True

def build_loader(validation_split: float, random_seed):
    logger.info("Building dataset")
    train_dataset = PCBDataset(args, "train")  # 會有 neg
    val_dataset = PCBDataset(args, "val")  # 不會有 neg
    eval_dataset = PCBDataset(args, "eval")
    test_dataset = PCBDataset(args, "test")
    logger.info("Build dataset done")

    # split train & val dataset
    dataset_size = len(train_dataset)
    indices = list(range(dataset_size))
    random.seed(random_seed)
    random.shuffle(indices)
    split = dataset_size - int(np.floor(validation_split * dataset_size))
    train_indices, val_indices = indices[:split], indices[split:]
    train_dataset = Subset(train_dataset, train_indices)
    val_dataset = Subset(val_dataset, val_indices)
    train_eval_dataset = Subset(eval_dataset, train_indices)
    val_eval_dataset = Subset(eval_dataset, val_indices)

    print(f"Train dataset size: {len(train_dataset)}")
    print(f"Val dataset size: {len(val_dataset)}")
    print(f"Test dataset size: {len(test_dataset)}")
    assert len(train_dataset) != 0, "ERROR, there is no data for training."

    # train_sampler = None
    # if get_world_size() > 1:
    #     train_sampler = DistributedSampler(dataset)

    train_loader = DataLoader(
        train_dataset,
        batch_size=args.batch_size,
        num_workers=cfg.TRAIN.NUM_WORKERS,
        pin_memory=True,
        # sampler=train_sampler
    )
    train_eval_loader = DataLoader(
        train_eval_dataset,
        batch_size=1,
        num_workers=cfg.TRAIN.NUM_WORKERS,
        pin_memory=True,
    )

    val_loader = DataLoader(
        val_dataset,
        batch_size=args.batch_size,
        num_workers=cfg.TRAIN.NUM_WORKERS,
        pin_memory=True,
    )
    val_eval_loader = DataLoader(
        val_eval_dataset,
        batch_size=1,
        num_workers=cfg.TRAIN.NUM_WORKERS,
        pin_memory=True,
    )

    test_loader = DataLoader(
        test_dataset,
        batch_size=1,
        num_workers=cfg.TRAIN.NUM_WORKERS,
        pin_memory=True
    )

    return train_loader, val_loader, \
        train_eval_loader, val_eval_loader, \
        test_loader

def build_opt_lr(model, current_epoch=0):
    for param in model.backbone.parameters():
        param.requires_grad = False
    for m in model.backbone.modules():
        if isinstance(m, nn.BatchNorm2d):
            m.eval()
    if current_epoch >= cfg.BACKBONE.TRAIN_EPOCH:
        for layer in cfg.BACKBONE.TRAIN_LAYERS:
            for param in getattr(model.backbone, layer).parameters():
                param.requires_grad = True
            for m in getattr(model.backbone, layer).modules():
                if isinstance(m, nn.BatchNorm2d):
                    m.train()
    print(f"current_epoch: {current_epoch}")

    trainable_params = []
    trainable_params += [{'params': filter(lambda x: x.requires_grad,
                                           model.backbone.parameters()),
                          'lr': cfg.BACKBONE.LAYERS_LR * cfg.TRAIN.BASE_LR}]

    if cfg.ADJUST.ADJUST:
        trainable_params += [{'params': model.neck.parameters(),
                              'lr': cfg.TRAIN.BASE_LR}]

    trainable_params += [{'params': model.rpn_head.parameters(),
                          'lr': cfg.TRAIN.BASE_LR}]

    if cfg.MASK.MASK:
        trainable_params += [{'params': model.mask_head.parameters(),
                              'lr': cfg.TRAIN.BASE_LR}]

    if cfg.REFINE.REFINE:
        trainable_params += [{'params': model.refine_head.parameters(),
                              'lr': cfg.TRAIN.LR.BASE_LR}]

    optimizer = torch.optim.SGD(trainable_params,
                                momentum=cfg.TRAIN.MOMENTUM,
                                weight_decay=cfg.TRAIN.WEIGHT_DECAY)

    lr_scheduler = build_lr_scheduler(optimizer, epochs=args.epoch)
    # lr_scheduler.step(cfg.TRAIN.START_EPOCH)
    # lr_scheduler.step()         # https://github.com/allenai/allennlp/issues/3922
    return optimizer, lr_scheduler

def log_grads(model, tb_writer, tb_index):
    def weights_grads(model):
        grad = {}
        weights = {}
        for name, param in model.named_parameters():
            if param.grad is not None:
                grad[name] = param.grad
                weights[name] = param.data
        return grad, weights

    grad, weights = weights_grads(model)
    feature_norm, rpn_norm = 0, 0
    for k, g in grad.items():
        _norm = g.data.norm(2)
        weight = weights[k]
        w_norm = weight.norm(2)
        if 'feature' in k:
            feature_norm += _norm ** 2
        else:
            rpn_norm += _norm ** 2

        tb_writer.add_scalar('grad_all/'+k.replace('.', '/'),
                             _norm, tb_index)
        tb_writer.add_scalar('weight_all/'+k.replace('.', '/'),
                             w_norm, tb_index)
        tb_writer.add_scalar('w-g/'+k.replace('.', '/'),
                             w_norm/(1e-20 + _norm), tb_index)
    tot_norm = feature_norm + rpn_norm
    tot_norm = tot_norm ** 0.5
    feature_norm = feature_norm ** 0.5
    rpn_norm = rpn_norm ** 0.5

    tb_writer.add_scalar('grad/tot', tot_norm, tb_index)
    tb_writer.add_scalar('grad/feature', feature_norm, tb_index)
    tb_writer.add_scalar('grad/rpn', rpn_norm, tb_index)

def train(
    train_loader,
    val_loader,
    train_eval_loader,
    val_eval_loader,
    test_loader,
    model,
    optimizer,
    lr_scheduler,
    tb_writer,
    model_dir
):
    cur_lr = lr_scheduler.get_cur_lr()
    rank = get_rank()

    average_meter = AverageMeter()

    def is_valid_number(x):
        return not(math.isnan(x) or math.isinf(x) or x > 1e4)

    world_size = get_world_size()
    num_per_epoch = len(train_loader.dataset) // args.epoch // (args.batch_size * world_size)

    start_epoch = cfg.TRAIN.START_EPOCH
    # epoch = start_epoch

    if not os.path.exists(cfg.TRAIN.MODEL_DIR) and \
            get_rank() == 0:
        os.makedirs(cfg.TRAIN.MODEL_DIR)

    # logger.info("model\n{}".format(describe(model.module)))
    end = time.time()

    for epoch in range(args.epoch):
        # one epoch
        logger.info(f"Epoch: {epoch + 1}")
        # Start training backbone at TRAIN_EPOCH
        # 他是把 backbone model 的 params 變成 requires_grad=True
        if (epoch + 1) == cfg.BACKBONE.TRAIN_EPOCH:
            logger.info('Start training backbone.')
            optimizer, lr_scheduler = build_opt_lr(model.module, epoch)
        cur_lr = lr_scheduler.get_cur_lr()

        train_loss = dict(cls=0.0, loc=0.0, total=0.0)
        val_loss = dict(cls=0.0, loc=0.0, total=0.0)
        epoch_start = time.time()

        ##########################################
        # Training
        ##########################################
        model.train()
        accum_batch_loss = 0
        for batch_idx, data in enumerate(train_loader):
            # one batch
            tb_idx = batch_idx
            # if batch_idx % num_per_epoch == 0 and batch_idx != 0:
            #     for idx, pg in enumerate(optimizer.param_groups):
            #         logger.info('epoch {} lr {}'.format(epoch, pg['lr']))
            #         if rank == 0:
            #             tb_writer.add_scalar('lr/group{}'.format(idx+1),
            #                                 pg['lr'], tb_idx)

            # data_time = average_reduce(time.time() - end)
            # if rank == 0:
            #     tb_writer.add_scalar('time/data', data_time, tb_idx)

            # Forwarding
            outputs = model(data)

            print(
                f"cls_loss: {outputs['cls']:<6.3f}"
                f" | loc_loss: {outputs['loc']:<6.3f}"
                f" | total_loss: {outputs['total']:<6.3f}"
            )

            # train_loss 會個別對應 outputs 的 key 後做疊加
            train_loss = {key: value + outputs[key] for key, value in train_loss.items()}

            accum_batch_loss = outputs['total']
            accum_batch_loss.backward()
            if is_valid_number(accum_batch_loss.data.item()):
                # accumulate gradients
                if ((batch_idx + 1) % args.accum_iter == 0) or ((batch_idx + 1) == len(train_loader)):
                    # print("Update model weights")
                    optimizer.step()
                    optimizer.zero_grad()
                    # accum_batch_loss.backward()
                    reduce_gradients(model)

                    if rank == 0 and cfg.TRAIN.LOG_GRADS:
                        log_grads(model.module, tb_writer, tb_idx)

                    # clip gradient
                    clip_grad_norm_(model.parameters(), cfg.TRAIN.GRAD_CLIP)
                    accum_batch_loss = 0

        epoch_end = time.time()
        print(f"--- epoch duration: {epoch_end - epoch_start} s ---")

        lr_scheduler.step()

        train_loss = {key: value / len(train_loader) for key, value in train_loss.items()}
        print("--- Train ---")
        print(
            f"cls_loss: {train_loss['cls']:<6.3f}"
            f" | loc_loss: {train_loss['loc']:<6.3f}"
            f" | total_loss: {train_loss['total']:<6.3f}"
        )

        ##########################################
        # Validation
        ##########################################
        # for idx, data in enumerate(val_loader):
        #     with torch.no_grad():
        #         outputs = model(data)

        #     batch_cls_loss = outputs['cls']
        #     batch_loc_loss = outputs['loc']
        #     batch_total_loss = outputs['total']
        #     val_loss['cls'] += batch_cls_loss
        #     val_loss['loc'] += batch_loc_loss
        #     val_loss['total'] += batch_total_loss

        # val_loss = {key: value / len(train_loader) for key, value in val_loss.items()}
        # print("--- Validation ---")
        # print(f"cls_loss: {val_loss['cls']:<6.3f} | loc_loss: {val_loss['loc']:<6.3f} | total_loss: {val_loss['total']:<6.3f}")

        ##########################################
        # Evaluating (once every EVAL_FREQ)
        ##########################################
        if (epoch + 1) % cfg.TRAIN.EVAL_FREQ == 0:
            dummy_model_name = "dummy_model"
            dummy_model_path = os.path.join("./save_models/dummy_model", f"{dummy_model_name}.pth")
            torch.save({
                'epoch': epoch,
                'state_dict': model.module.state_dict(),
                'optimizer': optimizer.state_dict()
            }, dummy_model_path)
            print(f"Save dummy_model: {dummy_model_path}")

            # Create tracker model
            eval_model = ModelBuilder()
            eval_model = load_pretrain(eval_model, dummy_model_path).cuda().eval()
            tracker = build_tracker(eval_model)

            logger.info("Train evaluating")
            train_metrics = evaluate(train_eval_loader, tracker)

            # logger.info("Validation evaluating")
            # val_metrics = evaluate(val_eval_loader, tracker)

            logger.info("Test evaluating")
            test_metrics = evaluate(test_loader, tracker)

            wandb.log({
                "train_metrics": {
                    "precision": train_metrics['precision'],
                    "recall": train_metrics['recall']
                },
                # "val_metrics": {
                #     "precision": val_metrics['precision'],
                #     "recall": val_metrics['recall']
                # },
                "test_metrics": {
                    "precision": test_metrics['precision'],
                    "recall": test_metrics['recall']
                }
            }, commit=False)

        wandb.log({
            "train": {
                "cls_loss": train_loss['cls'],
                "loc_loss": train_loss['loc'],
                "total_loss": train_loss['total']
            },
            # "val": {
            #     "cls_loss": val_loss['cls'],
            #     "loc_loss": val_loss['loc'],
            #     "total_loss": val_loss['total']
            # },
            "epoch": epoch + 1
        }, commit=True)

        # batch_time = time.time() - end
        # batch_info = {}
        # batch_info['batch_time'] = average_reduce(batch_time)
        # batch_info['data_time'] = average_reduce(data_time)
        # for k, v in sorted(outputs.items()):
        #     batch_info[k] = average_reduce(v.data.item())

        # average_meter.update(**batch_info)

        ##########################################
        # Save model
        ##########################################
        # if (get_rank() == 0) and ((epoch + 1) % cfg.TRAIN.SAVE_MODEL_FREQ == 0):
        #     # Save model path
        #     model_path = os.path.join(model_dir, f"model_e{epoch + 1}.pth")
        #     torch.save({
        #         'epoch': epoch + 1,
        #         'state_dict': model.module.state_dict(),
        #         'optimizer': optimizer.state_dict()
        #     }, model_path)
        #     print(f"Save model to: {model_path}")

        end = time.time()

def main():
    rank, world_size = dist_init()
    logger.info("init done")

    # load cfg
    cfg.merge_from_file(args.cfg)

    if rank == 0:
        if not os.path.exists(cfg.TRAIN.LOG_DIR):
            os.makedirs(cfg.TRAIN.LOG_DIR)
        init_log('global', logging.INFO)
        if cfg.TRAIN.LOG_DIR:
            add_file_handler('global',
                             os.path.join(cfg.TRAIN.LOG_DIR, 'logs.txt'),
                             logging.INFO)

        logger.info("Version Information: \n{}\n".format(commit()))
        # logger.info("config \n{}".format(json.dumps(cfg, indent=4)))

    # build dataset loader
    train_loader, val_loader, train_eval_loader, val_eval_loader, test_loader \
        = build_loader(cfg.DATASET.VALIDATION_SPLIT, random_seed=42)

    # create model
    model = ModelBuilder().cuda()

    # load pretrained backbone weights
    if cfg.BACKBONE.PRETRAINED:
        cur_path = os.path.dirname(os.path.realpath(__file__))
        backbone_path = os.path.join(cur_path, '../', cfg.BACKBONE.PRETRAINED)
        load_pretrain(model.backbone, backbone_path)

    # # create tensorboard writer
    if rank == 0 and cfg.TRAIN.LOG_DIR:
        tb_writer = SummaryWriter(cfg.TRAIN.LOG_DIR)
    else:
        tb_writer = None

    # build optimizer and lr_scheduler
    optimizer, lr_scheduler = build_opt_lr(model,
                                           cfg.TRAIN.START_EPOCH)

    # resume training
    if cfg.TRAIN.RESUME:
        logger.info("resume from {}".format(cfg.TRAIN.RESUME))
        assert os.path.isfile(cfg.TRAIN.RESUME), \
            '{} is not a valid file.'.format(cfg.TRAIN.RESUME)
        model, optimizer, cfg.TRAIN.START_EPOCH = \
            restore_from(model, optimizer, cfg.TRAIN.RESUME)
    # load pretrain
    elif cfg.TRAIN.PRETRAINED:
        load_pretrain(model, cfg.TRAIN.PRETRAINED)
    dist_model = DistModule(model)

    logger.info(lr_scheduler)
    logger.info("model prepare done")

    # Create save model directory
    model_dir = os.path.join(
        cfg.TRAIN.MODEL_DIR,
        f"{args.dataset_name}",
        f"{args.criteria}",
        f"{args.dataset_name}_{args.criteria}_{args.bk}_neg{args.neg}_k{args.anchors}_x{cfg.TRAIN.SEARCH_SIZE}_{args.crop_method}_bg{args.bg}_e{args.epoch}_b{args.batch_size}"
    )
    # create_dir(model_dir)
    print(f"Save model to dir: {model_dir}")

    # Start training
    train(train_loader, val_loader, train_eval_loader, val_eval_loader, test_loader, dist_model, optimizer, lr_scheduler, tb_writer, model_dir)

if __name__ == '__main__':
    seed_torch(args.seed)

    # constants = {
    #     "dataset": args.dataset_name,
    #     "criteria": args.criteria,
    #     "backbone": args.bk,
    #     "backbone_train": cfg.BACKBONE.TRAIN_EPOCH,
    #     "neg": args.neg,
    #     "anchor": args.anchors,
    #     "search": cfg.TRAIN.SEARCH_SIZE,
    #     "crop_method": args.crop_method,
    #     "background": args.bg,
    #     "epochs": args.epoch,
    #     "batch_size": args.batch_size,
    #     "lr": cfg.TRAIN.BASE_LR,
    #     "weight_decay": cfg.TRAIN.WEIGHT_DECAY,
    # }

    # wandb.init(
    #     project="SiamRPN++",
    #     entity="adrien88",
    #     name=f"{args.dataset_name}_{args.criteria}_{args.bk}_neg{args.neg}_k{args.anchors}_x{cfg.TRAIN.SEARCH_SIZE}_{args.crop_method}_bg{args.bg}_e{args.epoch}_b{args.batch_size}",
    #     config=constants
    # )

    main()