from django import forms
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db import IntegrityError
from django.db.models import Count, Q, F
from django.http import HttpResponseRedirect
from django.shortcuts import redirect
from django.views.decorators.http import require_POST
from django.views.generic import UpdateView, DetailView, TemplateView, ListView
from django.core.exceptions import ObjectDoesNotExist, SuspiciousOperation
from django.core.urlresolvers import reverse_lazy
from django.contrib import messages
from django.views.generic.detail import SingleObjectMixin

from docapp.models import (PacienteEmpresa, Occupational, Audiology, Visiometry, Altura, AntecedentesLaborales, Riesgos,
                           Accidentes, SimpleExam, Examinacion, Consulta)
from docapp.forms import (OcupaForm,
                          ant_familiares_section,
                          ant_gineco_section,
                          revision_sistemas_section,
                          biometria_section,
                          habito_alcohol_section, habito_cigarillo_section, habito_droga_section,
                          habito_general_section,
                          examen_fisico_general_section, examen_fisico_abdomen_section, examen_fisico_boca_section,
                          examen_fisico_columna_section, examen_fisico_corazon_section, examen_fisico_cuello_section,
                          examen_fisico_extremidades_section, examen_fisico_genito_unitario_section,
                          examen_fisico_nariz_section, examen_fisico_neurologico_section, examen_fisico_oidos_section,
                          examen_fisico_ojos_section, examen_fisico_torax_pulmones_section,
                          conclusion_ingreso_section,
                          conclusion_periodico_section,
                          conclusion_post_incapacidad_section,
                          conclusion_retiro_section)

from docapp.forms import (AudioForm,
                          ananmesis_section,
                          ant_familiar_section,
                          ant_otro_section,
                          exposicion_audifonos_section, exposicion_moto_section, exposicion_auto_section,
                          exposicion_pesada_section,
                          estado_actual_ruido_molestia_section, estado_actual_volumen_tv_section,
                          estado_actual_frases_repetidas_section, estado_actual_escucha_section,
                          estado_actual_escucha_ruido_section,
                          audiometria_section)

from docapp.forms import (VisioForm, sintomas_section, ant_enfermedad_section, ant_uso_lentes_section,
                          ant_extra_exams, agudeza_section, cronomatica_section,
                          AntLaboralesForm, hazards_inlineformset, accident_inlineformset)

from docapp.forms import AlturaForm, question_section, SimpleExamForm

from docproject.helpers.chekers import CheckDoctor, CheckLaboratory, CheckUser
from docproject.helpers.customs import (FormViewPutExtra, FormsetPostManager, BaseRegisterExamBehavior,
                                        BaseExamUpdateBehavior)
from docapp.choices import ExamStates
from django.shortcuts import get_object_or_404

from accounts.models import DoctorProfile, ReceptionProfile

class RegisterOccupational(LoginRequiredMixin, CheckDoctor, BaseRegisterExamBehavior, FormsetPostManager,
                           FormViewPutExtra):
    model = Occupational
    form_class = OcupaForm
    template_name = 'docapp/register/exams/occupational.html'
    extra_context = {'exam_name': 'ocupacional',
                     'parent_object_key': 'ocupacional_id',
                     'child_name': 'ocupacional',
                     'formsets': [
                         {'section_name': 'ant_familiares',
                          'title': 'Antecedentes Familiares',
                          'form': ant_familiares_section},
                         None,
                         {'section_name': 'revision_sistemas',
                          'title': 'Revision por Sistemas',
                          'form': revision_sistemas_section},
                         # Habitos
                         {'section_name': 'habitos_generales',
                          'title': 'Habitos Generales',
                          'form': habito_general_section},
                         {'section_name': 'habito_alcohol',
                          'title': 'Habito Alcohol',
                          'form': habito_alcohol_section},
                         {'section_name': 'habito_cigarrillo',
                          'title': 'Habito Cigarillo',
                          'form': habito_cigarillo_section},
                         {'section_name': 'habito_droga',
                          'title': 'Habito Droga',
                          'form': habito_droga_section},
                         # Examen Fisico
                         {'section_name': 'aspecto_general',
                          'title': 'Aspecto General',
                          'form': examen_fisico_general_section},
                         {'section_name': 'biometria',
                          'title': 'Biometria',
                          'form': biometria_section},
                         # # Organos de los sentidos
                         {'section_name': 'org_boca',
                          'title': 'Boca',
                          'form': examen_fisico_boca_section},
                         {'section_name': 'org_nariz',
                          'title': 'Nariz',
                          'form': examen_fisico_nariz_section},
                         {'section_name': 'org_oidos',
                          'title': 'Oidos',
                          'form': examen_fisico_oidos_section},
                         {'section_name': 'org_ojos',
                          'title': 'Ojos',
                          'form': examen_fisico_ojos_section},
                         # # Fin Organos
                         {'section_name': 'exm_cuello',
                          'title': 'Cuello',
                          'form': examen_fisico_cuello_section},
                         {'section_name': 'exm_torax_pulmones',
                          'title': 'Torax y Pulmones',
                          'form': examen_fisico_torax_pulmones_section},
                         {'section_name': 'exm_corazon',
                          'title': 'Corazon',
                          'form': examen_fisico_corazon_section},
                         {'section_name': 'exm_abdomen',
                          'title': 'Abdomen',
                          'form': examen_fisico_abdomen_section},
                         {'section_name': 'exm_columna',
                          'title': 'Columna',
                          'form': examen_fisico_columna_section},
                         {'section_name': 'exm_extremidades',
                          'title': 'Extremidades',
                          'form': examen_fisico_extremidades_section},
                         {'section_name': 'exm_neurologico',
                          'title': 'Neurologico',
                          'form': examen_fisico_neurologico_section},
                         {'section_name': 'exm_genito_unitario',
                          'title': 'Genito Unitario',
                          'form': examen_fisico_genito_unitario_section},
                         # Fin examen fisico
                         None
                     ]
                     }

    def get_context_data(self, **kwargs):
        examination = self.get_object()
        examination_patient = examination.paciente_id
        if examination_patient.sexo == 'femenino' and self.extra_context['formsets'][1] is None:
            self.extra_context['formsets'][1] = {'section_name': 'ant_gineco',
                                                 'title': 'Antecedentes Gineco-Obstricos',
                                                 'form': ant_gineco_section}
        if self.extra_context['formsets'][21] is None:
            conclusion_section = {'section_name': 'conclusion',
                                  'title': 'Conclusion',
                                  'form': None}
            if examination.tipo == 'ingreso':
                conclusion_section.update({'form': conclusion_ingreso_section})
            elif examination.tipo == 'periodico':
                conclusion_section.update({'form': conclusion_periodico_section})
            elif examination.tipo == 'retiro' or examination.tipo == 'reubicacion':
                conclusion_section.update({'form': conclusion_retiro_section})
            elif examination.tipo == 'post-incapacidad':
                conclusion_section.update({'form': conclusion_post_incapacidad_section})
            else:
                raise SuspiciousOperation("Contact Admin")

            self.extra_context['formsets'][21] = conclusion_section
        return super(RegisterOccupational, self).get_context_data(**kwargs)

register_occupational = RegisterOccupational.as_view()

class UpdateOccupational(LoginRequiredMixin, CheckDoctor, BaseExamUpdateBehavior, FormsetPostManager, UpdateView):
    model = Occupational
    form_class = OcupaForm
    template_name = 'docapp/register/exams/occupational.html'
    extra_context = {'exam_name': 'ocupacional',
                     'parent_object_key': 'ocupacional_id',
                     'formsets': [
                         {'section_name': 'ant_familiares',
                          'title': 'Antecedentes Familiares',
                          'form': ant_familiares_section},
                         None,
                         {'section_name': 'revision_sistemas',
                          'title': 'Revision por Sistemas',
                          'form': revision_sistemas_section},
                         # Habitos
                         {'section_name': 'habitos_generales',
                          'title': 'Habitos Generales',
                          'form': habito_general_section},
                         {'section_name': 'habito_alcohol',
                          'title': 'Habito Alcohol',
                          'form': habito_alcohol_section},
                         {'section_name': 'habito_cigarrillo',
                          'title': 'Habito Cigarillo',
                          'form': habito_cigarillo_section},
                         {'section_name': 'habito_droga',
                          'title': 'Habito Droga',
                          'form': habito_droga_section},
                         # Examen Fisico
                         {'section_name': 'aspecto_general',
                          'title': 'Aspecto General',
                          'form': examen_fisico_general_section},
                         {'section_name': 'biometria',
                          'title': 'Biometria',
                          'form': biometria_section},
                         # # Organos de los sentidos
                         {'section_name': 'org_boca',
                          'title': 'Boca',
                          'form': examen_fisico_boca_section},
                         {'section_name': 'org_nariz',
                          'title': 'Nariz',
                          'form': examen_fisico_nariz_section},
                         {'section_name': 'org_oidos',
                          'title': 'Oidos',
                          'form': examen_fisico_oidos_section},
                         {'section_name': 'org_ojos',
                          'title': 'Ojos',
                          'form': examen_fisico_ojos_section},
                         # # Fin Organos
                         {'section_name': 'exm_cuello',
                          'title': 'Cuello',
                          'form': examen_fisico_cuello_section},
                         {'section_name': 'exm_torax_pulmones',
                          'title': 'Torax y Pulmones',
                          'form': examen_fisico_torax_pulmones_section},
                         {'section_name': 'exm_corazon',
                          'title': 'Corazon',
                          'form': examen_fisico_corazon_section},
                         {'section_name': 'exm_abdomen',
                          'title': 'Abdomen',
                          'form': examen_fisico_abdomen_section},
                         {'section_name': 'exm_columna',
                          'title': 'Columna',
                          'form': examen_fisico_columna_section},
                         {'section_name': 'exm_extremidades',
                          'title': 'Extremidades',
                          'form': examen_fisico_extremidades_section},
                         {'section_name': 'exm_neurologico',
                          'title': 'Neurologico',
                          'form': examen_fisico_neurologico_section},
                         {'section_name': 'exm_genito_unitario',
                          'title': 'Genito Unitario',
                          'form': examen_fisico_genito_unitario_section},
                         # Fin examen fisico
                         None
                     ]
                     }

    def get_context_data(self, **kwargs):
        examination = self.get_object().examinacion_id
        examination_patient = examination.paciente_id
        if examination_patient.sexo == 'femenino':
            self.extra_context['formsets'][1] = {'section_name': 'ant_gineco',
                                                 'title': 'Antecedentes Gineco-Obstricos',
                                                 'form': ant_gineco_section}
        conclusion_section = {'section_name': 'conclusion',
                              'title': 'Conclusion',
                              'form': None}
        if examination.tipo == 'ingreso':
            conclusion_section.update({'form': conclusion_ingreso_section})
        elif examination.tipo == 'periodico':
            conclusion_section.update({'form': conclusion_periodico_section})
        elif examination.tipo == 'retiro' or examination.tipo == 'reubicacion':
            conclusion_section.update({'form': conclusion_retiro_section})
        elif examination.tipo == 'post-incapacidad':
            conclusion_section.update({'form': conclusion_post_incapacidad_section})
        else:
            raise SuspiciousOperation("Contact Admin")

        self.extra_context['formsets'][21] = conclusion_section
        return super(UpdateOccupational, self).get_context_data(**kwargs)

update_ocupacional = UpdateOccupational.as_view()

class RegisterAudiology(LoginRequiredMixin, CheckDoctor, BaseRegisterExamBehavior, FormsetPostManager,
                        FormViewPutExtra):
    model = Audiology
    form_class = AudioForm
    template_name = 'docapp/register/exams/audilogy.html'
    extra_context = {'exam_name': 'audiologia',
                     'parent_object_key': 'audiologia_id',
                     'child_name': 'audiologia',
                     'formsets': [
                         {'section_name': 'ananmesis',
                          'title': 'Ananmesis',
                          'form': ananmesis_section},
                         {'section_name': 'ant_familiar',
                          'title': 'Antecedentes Familiares',
                          'form': ant_familiar_section},
                         {'section_name': 'ant_otros',
                          'title': 'Otros Antecedentes',
                          'form': ant_otro_section},
                         # Exposiciones
                         {'section_name': 'exp_audifonos',
                          'title': 'Uso de Audifonos',
                          'form': exposicion_audifonos_section},
                         {'section_name': 'exo_moto',
                          'title': 'Uso de Motocicleta',
                          'form': exposicion_moto_section},
                         {'section_name': 'exp_automotriz',
                          'title': 'Uso de Automotriz',
                          'form': exposicion_auto_section},
                         {'section_name': 'exp_maq_pesada',
                          'title': 'Uso de Maquinaria Pesada',
                          'form': exposicion_pesada_section},
                         # Estado Actual
                         {'section_name': 'est_ruido_molestia',
                          'title': '¿Le molesta el ruido?',
                          'form': estado_actual_ruido_molestia_section},
                         {'section_name': 'est_vol_tv',
                          'title': '¿Debe subir el volumen del televisor?',
                          'form': estado_actual_volumen_tv_section},
                         {'section_name': 'est_fra_repite',
                          'title': '¿En una conversación le repiten las frases?',
                          'form': estado_actual_frases_repetidas_section},
                         {'section_name': 'est_esc_oye',
                          'title': '¿Escucha bien?',
                          'form': estado_actual_escucha_section},
                         {'section_name': 'est_esc_ruido',
                          'title': '¿Escucha bien cuando hay ruido?',
                          'form': estado_actual_escucha_ruido_section},
                         # End Estado Actual
                         {'section_name': 'audiometria',
                          'title': 'Audiometria',
                          'form': audiometria_section},
                     ]
                     }

register_audiology = RegisterAudiology.as_view()

class UpdateAudiology(LoginRequiredMixin, CheckDoctor, BaseExamUpdateBehavior, FormsetPostManager, UpdateView):
    model = Audiology
    form_class = AudioForm
    template_name = 'docapp/register/exams/audilogy.html'
    extra_context = {'exam_name': 'audiologia',
                     'parent_object_key': 'audiologia_id',
                     'formsets': [
                         {'section_name': 'ananmesis',
                          'title': 'Ananmesis',
                          'form': ananmesis_section},
                         {'section_name': 'ant_familiar',
                          'title': 'Antecedentes Familiares',
                          'form': ant_familiar_section},
                         {'section_name': 'ant_otros',
                          'title': 'Otros Antecedentes',
                          'form': ant_otro_section},
                         # Exposiciones
                         {'section_name': 'exp_audifonos',
                          'title': 'Uso de Audifonos',
                          'form': exposicion_audifonos_section},
                         {'section_name': 'exo_moto',
                          'title': 'Uso de Motocicleta',
                          'form': exposicion_moto_section},
                         {'section_name': 'exp_automotriz',
                          'title': 'Uso de Automotriz',
                          'form': exposicion_auto_section},
                         {'section_name': 'exp_maq_pesada',
                          'title': 'Uso de Maquinaria Pesada',
                          'form': exposicion_pesada_section},
                         # Estado Actual
                         {'section_name': 'est_ruido_molestia',
                          'title': '¿Le molesta el ruido?',
                          'form': estado_actual_ruido_molestia_section},
                         {'section_name': 'est_vol_tv',
                          'title': '¿Debe subir el volumen del televisor?',
                          'form': estado_actual_volumen_tv_section},
                         {'section_name': 'est_fra_repite',
                          'title': '¿En una conversación le repiten las frases?',
                          'form': estado_actual_frases_repetidas_section},
                         {'section_name': 'est_esc_oye',
                          'title': '¿Escucha bien?',
                          'form': estado_actual_escucha_section},
                         {'section_name': 'est_esc_ruido',
                          'title': '¿Escucha bien cuando hay ruido?',
                          'form': estado_actual_escucha_ruido_section},
                         # End Estado Actual
                         {'section_name': 'audiometria',
                          'title': 'Audiometria',
                          'form': audiometria_section},
                     ]
                     }

update_audiologia = UpdateAudiology.as_view()

class RegisterVisiometry(LoginRequiredMixin, CheckDoctor, BaseRegisterExamBehavior, FormsetPostManager,
                         FormViewPutExtra):
    model = Visiometry
    form_class = VisioForm
    template_name = 'docapp/register/exams/visiometry.html'
    success_url = reverse_lazy('docapp:doctor_own_examinations')
    extra_context = {'exam_name': 'visiometria',
                     'parent_object_key': 'visiometria_id',
                     'child_name': 'visiometria',
                     'formsets': [
                         {'section_name': 'sintomas',
                          'title': 'Sintomas',
                          'form': sintomas_section},
                         {'section_name': 'ant_enfermedad',
                          'title': 'Antecedentes de Enfermedades',
                          'form': ant_enfermedad_section},
                         {'section_name': 'ant_uso_lentes',
                          'title': 'Antecedentes de Uso de Lentes',
                          'form': ant_uso_lentes_section},
                         {'section_name': 'ant_extra_exams',
                          'title': 'Antecedentes de Examenes',
                          'form': ant_extra_exams},
                         {'section_name': 'agudeza',
                          'title': 'Agudeza',
                          'form': agudeza_section},
                         {'section_name': 'cronomatica',
                          'title': 'Cronomatica',
                          'form': cronomatica_section}
                     ]
                     }

register_visiometry = RegisterVisiometry.as_view()

class UpdateVisiometry(LoginRequiredMixin, CheckDoctor, BaseExamUpdateBehavior, FormsetPostManager, UpdateView):
    model = Visiometry
    form_class = VisioForm
    template_name = 'docapp/register/exams/visiometry.html'
    extra_context = {'exam_name': 'visiometria',
                     'parent_object_key': 'visiometria_id',
                     'formsets': [
                         {'section_name': 'sintomas',
                          'title': 'Sintomas',
                          'form': sintomas_section},

                         {'section_name': 'ant_enfermedad',
                          'title': 'Antecedentes de Enfermedades',
                          'form': ant_enfermedad_section},

                         {'section_name': 'ant_uso_lentes',
                          'title': 'Antecedentes de Uso de Lentes',
                          'form': ant_uso_lentes_section},

                         {'section_name': 'ant_extra_exams',
                          'title': 'Antecedentes de Examenes',
                          'form': ant_extra_exams},

                         {'section_name': 'agudeza',
                          'title': 'Agudeza',
                          'form': agudeza_section},

                         {'section_name': 'cronomatica',
                          'title': 'Cronomatica',
                          'form': cronomatica_section}
                     ]
                     }

update_visiometria = UpdateVisiometry.as_view()

class RegisterAltura(LoginRequiredMixin, CheckDoctor, BaseRegisterExamBehavior, FormsetPostManager, FormViewPutExtra):
    model = Altura
    form_class = AlturaForm
    template_name = 'docapp/register/exams/altura.html'
    extra_context = {'exam_name': 'altura',
                     'parent_object_key': 'altura_id',
                     'child_name': 'altura',
                     'formsets': [
                         {'section_name': 'preguntas',
                          'title': 'Estado',
                          'form': question_section},
                     ]
                     }

register_altura = RegisterAltura.as_view()

class UpdateAltura(LoginRequiredMixin, CheckDoctor, BaseExamUpdateBehavior, FormsetPostManager, UpdateView):
    model = Altura
    form_class = AlturaForm
    template_name = 'docapp/register/exams/altura.html'
    extra_context = {'exam_name': 'altura',
                     'parent_object_key': 'altura_id',
                     'formsets': [
                         {'section_name': 'preguntas',
                          'title': 'Estado',
                          'form': question_section},
                     ]
                     }

update_altura = UpdateAltura.as_view()

class RegisterSimpleExam(LoginRequiredMixin, CheckDoctor, UpdateView):
    model = SimpleExam
    form_class = SimpleExamForm
    template_name = 'docapp/register/exams/simple.html'
    success_url = reverse_lazy('docapp:doctor_own_examinations')

register_simple_exam = RegisterSimpleExam.as_view()

# Process employ antecedent
class RegisterEmployAntecedent(CheckDoctor, LoginRequiredMixin, FormsetPostManager, FormViewPutExtra):
    pk_url_kwarg = 'person_id'
    form_class = AntLaboralesForm
    model = AntecedentesLaborales
    template_name = 'docapp/register/antecedent.html'
    success_url = reverse_lazy('docapp:doctor_own_examinations')
    model_to_filter = PacienteEmpresa
    context_object_2_name = 'person'
    extra_context = {'exam_name': 'Antecedente',
                     'parent_object_key': 'antecedente_id',
                     'formsets': [
                         {'section_name': 'riesgos',
                          'title': 'Riesgos',
                          'form': hazards_inlineformset},
                         {'section_name': 'accidentes',
                          'title': 'Accidentes',
                          'form': accident_inlineformset}
                     ]
                     }

    def _custom_save(self, form):
        person = self.get_object()
        form.create_by = self.request.user.doctor_profile
        form.person = person
        instance = form.save()
        if instance:
            person_name = person.__str__()
            messages.success(self.request, message=f"Antecedente de {person_name} register exitosamente")
        return instance

register_employ_antecedent = RegisterEmployAntecedent.as_view()

class UpdateEmployAntecedent(CheckDoctor, LoginRequiredMixin, FormsetPostManager, UpdateView):
    pk_url_kwarg = 'antecedent_id'
    context_object_name = 'antecedent'
    model = AntecedentesLaborales
    form_class = AntLaboralesForm
    template_name = 'docapp/register/antecedent.html'
    success_url = reverse_lazy('docapp:doctor_own_examinations')
    extra_context = {'parent_object_key': 'antecedente_id',
                     'formsets': [
                         {'section_name': 'riesgos',
                          'title': 'Riesgos',
                          'form': hazards_inlineformset},
                         {'section_name': 'accidentes',
                          'title': 'Accidentes',
                          'form': accident_inlineformset}
                     ]
                     }

    def form_valid(self, form):
        """ Overwrite form_valid to add missing information"""
        antecedent = self.get_object()
        form.create_by = self.request.user.doctor_profile
        form.person = antecedent.persona
        return super(UpdateEmployAntecedent, self).form_valid(form)

    def get_context_data(self, **kwargs):
        """ Overwrite get_context_data method to append formset necessary"""
        antecedent = self.get_object()
        try:
            data = Riesgos.objects.get(antecedente_id=antecedent)
            dict_data = vars(data)
            # Delete unneeded info
            dict_data.pop('_state', None)
            dict_data.pop('id', None)
            hazard_initial_data = [dict_data]
        except ObjectDoesNotExist:
            hazard_initial_data = []
        try:
            data = Accidentes.objects.filter(antecedente_id=antecedent)
            accident_initial_data = []
            for element in data:
                dict_data = vars(element)
                # Delete unneeded info
                dict_data.pop('_state', None)
                dict_data.pop('id', None)
                accident_initial_data.append(dict_data)
        except ObjectDoesNotExist:
            accident_initial_data = []

        accident_formset = forms.inlineformset_factory(parent_model=AntecedentesLaborales, model=Accidentes,
                                                       extra=len(accident_initial_data), can_delete=True,
                                                       fields='__all__', exclude=('registrado_por',))

        self.extra_context = {'parent_object_key': 'antecedente_id',
                              'formsets': [
                                  {'section_name': 'riesgos',
                                   'title': 'Riesgos',
                                   'form': hazards_inlineformset(initial=hazard_initial_data)},
                                  {'section_name': 'accidentes',
                                   'title': 'Accidentes',
                                   'form': accident_formset(initial=accident_initial_data)}
                              ]
                              }
        kwargs.update(self.extra_context)
        return super(UpdateEmployAntecedent, self).get_context_data(**kwargs)

update_employ_antecedent = UpdateEmployAntecedent.as_view()

class ListEmployAntecedents(CheckDoctor, LoginRequiredMixin, DetailView):
    pk_url_kwarg = 'person_id'
    context_object_name = 'paciente'
    model = PacienteEmpresa
    template_name = 'docapp/lists/antecedent_list.html'

list_employ_antecedents = ListEmployAntecedents.as_view()

class DetailEmployAntecedent(CheckDoctor, LoginRequiredMixin, DetailView):
    pk_url_kwarg = 'antecedent_id'
    model = AntecedentesLaborales
    context_object_name = 'antecedent'
    template_name = 'docapp/details/antecedent.html'

detail_employ_antecedent = DetailEmployAntecedent.as_view()

# End employ antecedent

# Examination process
class ListOwnExams(LoginRequiredMixin, CheckDoctor, TemplateView):
    template_name = 'docapp/lists/exam_list.html'

    def get_context_data(self, **kwargs):
        exams = None
        if hasattr(self.request.user.doctor_profile, 'examinaciones'):
            exams = self.request.user.doctor_profile.examinaciones.exclude(doctor_estado=ExamStates.FINALIZADO)
        kwargs.update({'exam_list': exams})
        return super(ListOwnExams, self).get_context_data(**kwargs)

own_examinations = ListOwnExams.as_view()

class DoctorTakeAExam(LoginRequiredMixin, CheckDoctor, SingleObjectMixin, TemplateView):
    object = None
    pk_url_kwarg = 'exam_id'
    model = Examinacion
    template_name = 'docapp/take_object.html'
    redirect_url = reverse_lazy('docapp:doctor_own_examinations')

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        kwargs.update({'redirect_url': self.redirect_url})
        return super(DoctorTakeAExam, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        exam = self.get_object()
        exam.manejador_por = request.user.doctor_profile
        exam.estado = ExamStates.INICIADO
        exam.doctor_estado = ExamStates.ASIGNADO
        try:
            exam.save()
        except IntegrityError:
            messages.error(message='Examinacion NO Asignada', request=request)
        else:
            messages.success(message='Examinacion Asignada Exitosamente', request=request)
        return redirect('docapp:doctor_own_examinations')

take_a_exam = DoctorTakeAExam.as_view()

class ListEndExams(LoginRequiredMixin, CheckDoctor, TemplateView):
    template_name = 'docapp/lists/exam_list.html'

    def get_context_data(self, **kwargs):
        exams = None
        if hasattr(self.request.user.doctor_profile, 'examinaciones'):
            exams = self.request.user.doctor_profile.examinaciones.filter(doctor_estado=ExamStates.FINALIZADO)
        kwargs.update({'exam_list': exams})
        return super(ListEndExams, self).get_context_data(**kwargs)

end_examinations = ListEndExams.as_view()

class DoctorEndExam(LoginRequiredMixin, CheckDoctor, SingleObjectMixin, TemplateView):
    object = None
    pk_url_kwarg = 'exam_id'
    model = Examinacion
    template_name = 'docapp/end_process.html'

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(DoctorEndExam, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        exam = self.get_object()
        if exam.get_doctor_process() == 100:
            exam.doctor_estado = ExamStates.FINALIZADO
            try:
                exam.save()
            except IntegrityError:
                messages.error(message='Examinacion NO Terminada', request=request)
            else:
                messages.success(message='Examinacion Asignada Exitosamente', request=request)
            return redirect('docapp:doctor_end_examinations')
        else:
            messages.warning(request, "No ha terminado todos los examenes")
            return redirect(request.path)

doctor_end_exam = DoctorEndExam.as_view()

# End examination process

# Views to process a consults process
class ListOwnConsults(LoginRequiredMixin, CheckDoctor, ListView):
    model = Consulta
    context_object_name = 'consults_list'
    template_name = 'docapp/lists/consults_list.html'

    def get_queryset(self):
        user = self.request.user.doctor_profile
        queryset = Consulta.objects.filter(Q(registrado_por=user.pk) & Q(estado=ExamStates.INICIADO))
        # Simulate group by clause -- https://stackoverflow.com/questions/629551/how-to-query-as-group-by-in-django
        # https://docs.djangoproject.com/en/dev/topics/db/aggregation/#topics-db-aggregation
        return queryset

lab_own_consults = ListOwnConsults.as_view()

class ListConsultas(CheckUser, LoginRequiredMixin, ListView):
    model = Consulta
    context_object_name = 'consults_list'
    template_name = 'docapp/lists/consults_list.html'

list_consults = ListConsultas.as_view()

class ListEnableConsultas(CheckUser, LoginRequiredMixin, ListView):
    model = Consulta
    context_object_name = 'consults_list'
    template_name = 'docapp/lists/consults_list.html'
    queryset = Consulta.objects.filter(estado=ExamStates.PENDIENTE)

list_consults_enable = ListEnableConsultas.as_view()

class ListEndConsultas(CheckUser, LoginRequiredMixin, ListView):
    model = Consulta
    context_object_name = 'consults_list'
    template_name = 'docapp/lists/consults_list.html'

    def get_queryset(self):
        queryset = Consulta.objects.filter(Q(registrado_por=self.request.user.pk) & Q(estado=ExamStates.FINALIZADO))
        return queryset

list_end_consults = ListEndConsultas.as_view()

@login_required
@require_POST
@user_passes_test(test_func=(lambda u: hasattr(u, 'doctor_profile') or u.is_superuser),
                  login_url=reverse_lazy('docapp:dashboard'))
def end_consult(request):
    consult_id = request.POST.get('consult_id', False)

    try:
        if consult_id:
            consult = Consulta.objects.select_for_update().get(id=int(consult_id))
            if consult.estado != ExamStates.FINALIZADO:
                consult.estado = ExamStates.FINALIZADO
                consult.save(update_fields=['estado'])
    except ObjectDoesNotExist as e:
        return HttpResponseRedirect(reverse_lazy('docapp:list_own_consults'), status=404)
    return HttpResponseRedirect(reverse_lazy('docapp:list_own_consults'), status=302)

@login_required
@require_POST
@user_passes_test(test_func=(lambda u: hasattr(u, 'doctor_profile') or u.is_superuser),
                  login_url=reverse_lazy('docapp:dashboard'))
def assign_consult(request):
    consult_id = request.POST.get('consult_id', False)

    try:
        if consult_id:
            consult = Consulta.objects.select_for_update().get(id=int(consult_id))
    except ObjectDoesNotExist as e:
        return HttpResponseRedirect(reverse_lazy('docapp:list_consults'), status=404)

    if consult.estado != ExamStates.INICIADO:
        consult.registrado_por = request.user.doctor_profile
        consult.estado = ExamStates.INICIADO
        consult.save(update_fields=['registrado_por', 'estado'])

    return HttpResponseRedirect(reverse_lazy('docapp:list_consults'), status=200)

# End process consult


limite = int(input("Ingresa el limite: "))
n=0
e=0
def factorial(n):
    if n < 0:
        return 0
    elif n == 0 or n == 1:
        return 1
    else:
        fact = 1
        while(n > 1):
            fact *= n
            n -= 1
        return fact

while n < limite:
    e += 1/factorial(n)
    n += 1

print("e: ",e)


import pytest
import sys
sys.path.append('..')
from sudokupy.cell import Cell
from sudokupy.deducers.deducer_base import  Transaction, Transactions

class TestTransaction:
    def test_cell(self):
        cell = Cell(0, 0, 0)
        t = Transaction(cell)
        assert t.cell == cell

    def test_add(self):
        cell = Cell(0, 0, 0)
        t = Transaction(cell)
        assert t.candidates == []

        t.add([3, 1, 2])
        assert t.candidates == [1, 2, 3]

        t.add([4])
        assert t.candidates == [1, 2, 3, 4]

        t.add([1])
        assert t.candidates == [1, 2, 3, 4]

    def test_eq(self):
        cell = Cell(0, 0, 0)
        cell2 = Cell(0, 0, 8)
        t1 = Transaction(cell)
        t2 = Transaction(cell2)

        assert t1 == t2

        cell3 = Cell(1, 1, 0)
        cell4 = Cell(1, 1, 7)
        t3 = Transaction(cell3)
        t4 = Transaction(cell4)

        assert t3 != t1
        assert t3 == t4

    def test_repr(self):
        cell = Cell(0, 0, 0)
        t = Transaction(cell)
        repr = t.__repr__()
        assert 'Transaction' in repr

class TestTransactions:
    def test_repr(self):
        t = Transactions()
        assert t.__str__().count('Transaction') == 0
        assert t.__repr__().count('Transaction') == 1

        t.add_transaction(Cell(0, 0, 0), [1])
        assert t.__str__().count('Transaction') == 1
        assert t.__repr__().count('Transaction') == 2

    def test_transactions(self):
        t = Transactions()
        assert t.transactions == []

        t.add_transaction(Cell(0, 0, 0), [2, 3])
        assert len(t.transactions) == 1
        assert isinstance(t.transactions[0], Transaction)

    def test_len(self):
        t = Transactions()
        assert len(t) == 0

        t.add_transaction(Cell(0, 0, 0), [1])
        assert len(t) == 1
        t.add_transaction(Cell(0, 0, 4), [3, 4, 5])
        assert len(t) == 1

        t.add_transaction(Cell(1, 1, 0), [7, 8, 9])
        assert len(t) == 2

    def test_extend_transactions(self):
        t1 = Transactions()
        t2 = Transactions()
        t3 = Transactions()

        assert len(t1.transactions) == 0
        t2.add_transaction(Cell(0, 0, 0), [1, 2])
        t1.extend_transactions(t2)
        assert len(t1.transactions) == 1
        assert isinstance(t1.transactions[0], Transaction)
        assert t1.transactions[0].candidates == [1, 2]
        t3.add_transaction(Cell(0, 0, 0), [3, 4])
        t1.extend_transactions(t3)
        assert len(t1.transactions) == 1
        assert t1.transactions[0].candidates == [1, 2, 3, 4]

        t2.add_transaction(Cell(8, 8, 0), [7, 8, 9])
        t1.extend_transactions(t2)
        assert len(t1.transactions) == 2
        assert t1.transactions[-1].candidates == [7, 8, 9]

    def test_clear_transactions(self):
        t = Transactions()
        t.add_transaction(Cell(0, 0, 0), [1, 2])
        assert len(t.transactions) == 1

        t.clear_transactions()
        assert len(t.transactions) == 0

    def test_get_transactions(self):
        t = Transactions()
        result = t.get_transactions()
        assert type(result) is list
        assert len(result) == 0

        t.add_transaction(Cell(0, 0, 0), [1, 2])
        result = t.get_transactions()
        assert type(result) is list
        assert len(result) == 1


import sublime
import sublime_plugin
import os
import unittest
import StringIO

g_executing_test_suite = None

test_suites = {
    'file_selector': ['file_selector_tests', 'file_selector_tests']
}

def print_to_view(view, obtain_content):
    edit = view.begin_edit()
    view.insert(edit, 0, obtain_content())
    view.end_edit(edit)
    view.set_scratch(True)
    view.set_name('unittest results')

    return view

class ShowGotoRelatedFileTestSuites(sublime_plugin.WindowCommand):

    def run(self):
        self.window.show_quick_panel(
            sorted(test_suites.keys()),
            self.run_suite
        )

    def run_suite(self, index):
        global g_executing_test_suite

        suite_name = sorted(test_suites.keys())[index]
        g_executing_test_suite = suite_name
        command_to_run = test_suites[suite_name][0]

        self.window.run_command(
            command_to_run,
            dict(suite_name=suite_name)
        )

class FileSelectorTestsCommand(sublime_plugin.WindowCommand):
    def run(self, suite_name):
        bucket = StringIO.StringIO()
        suite_name = test_suites[suite_name][1]
        suite = unittest.defaultTestLoader.loadTestsFromName(suite_name)
        unittest.TextTestRunner(stream=bucket, verbosity=1).run(suite)

        print_to_view(self.window.new_file(), bucket.getvalue)


import requests
from pprint import pprint

city = input('Enter your name of city: ')
api_key = 'Your api key from open weather'

units = 'metric'

url = f'https://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}&units={units}'

res = requests.get(url)
data = res.json()

# print(res)
pprint(data)

weather_stat = data['weather'][0]['description']
wind_speed = data['wind']['speed']
temperature = data['main']['temp']

# Get current weather status, temperature and wind_speed
print(weather_stat, temperature, wind_speed)


"""Plot the results of the `sortpref` binary.

Expects a `sortperf` executable in the current directory.
Writes image to `misc/out.svg`.

`pip install seaborn` should be enough to install this script's dependencies.

Notes:
  > By default, printf buffers its output, but the output is flushed on newline
  > or if a read occurs when the output is directed to a terminal.
  > When the output is directed to a file or a pipe,
  > the actual output only occurs when the buffer is full.
"""
from io import StringIO
from subprocess import Popen, PIPE, STDOUT

import matplotlib as mpl
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

def main():
    buf = StringIO()
    with Popen("./sortperf", stdout=PIPE, stderr=STDOUT, bufsize=1, text=True) as proc:
        for line in proc.stdout:
            print(line, end="")
            buf.write(line)
    datasets = buf.getvalue().split("\n\n")

    df = pd.DataFrame()
    for dataset in datasets[:-1]:
        algo, *table = dataset.split("\n")
        tmp = pd.read_fwf(StringIO("\n".join(table)))
        tmp["algorithm"] = algo
        df = pd.concat([df, tmp])

    df = df.melt(
        id_vars=["algorithm", "i"],
        value_vars=[x for x in df.columns if x.endswith("sort")],
        var_name="arrangement",
        value_name="time",
    )

    with plt.xkcd():
        # fiddle with some of the xkcd defaults
        # see https://matplotlib.org/3.1.1/_modules/matplotlib/pyplot.html#xkcd
        mpl.rcParams.update(
            {
                "path.effects": [
                    mpl.patheffects.withStroke(linewidth=2.5, foreground="w")
                ],
                "lines.linewidth": 2.25,
            }
        )

        g = sns.relplot(
            data=df,
            x="i",
            y="time",
            hue="algorithm",
            col="arrangement",
            kind="line",
            height=2.5,
            aspect=1.5,
            col_wrap=3,
        )
        g.set_axis_labels("Array size (2^N)", "Time (s)")
        g.set_titles("{col_name}")

    g.savefig("misc/out.svg")

    return 0

if __name__ == "__main__":
    raise SystemExit(main())


import numpy as np

from typing import Union, List, NamedTuple

class Move(NamedTuple):
    """A data struct to represent a tic-tac-toe move."""

    n_row: int
    n_col: int

class Codes:
    """A class to store game codes like markers and outcomes."""

    EMPTY = 0

    X_MARK = 1
    TIE = 0
    O_MARK = -1

class Board:
    """A Tic Tac Toe board."""

    SIDE_LENGTH = 3

    def __init__(self) -> None:
        """Initialize the empty board."""
        self.state = np.full(
            shape=(Board.SIDE_LENGTH, Board.SIDE_LENGTH), fill_value=Codes.EMPTY
        )

    def make_move(self, move: Move) -> None:
        """Make a move."""
        # Check that the square is empty.
        assert (
            self.state[move.n_row, move.n_col] == Codes.EMPTY
        ), f"{move} is not an empty square!"

        # Fill square with marker.
        marker = Board._get_marker(self.state)
        self.state[move.n_row, move.n_col] = marker

    def _get_marker(state: np.ndarray) -> int:
        """Return the marker of the player whose turn it is."""
        n_move = Board.get_n_move(state)

        # X if the turn is odd, O if even.
        if n_move % 2 == 1:
            return Codes.X_MARK
        else:
            return Codes.O_MARK

    def get_n_move(state: np.ndarray) -> int:
        """Find the move number based on the # of empty squares. Starts on move 1."""
        n_move = (9 - Board._get_n_empty(state)) + 1
        return n_move

    def _get_n_empty(state: np.ndarray) -> int:
        """Find the number of empty squares."""
        n_empty = np.sum(state == Codes.EMPTY)
        return n_empty

    def check_win(state: np.ndarray) -> Union[None, int]:
        """Check if there is a winner."""
        # A player has won if their marker is the mean of a slice.
        # Take row, column means.
        row_means = state.mean(axis=1)
        col_means = state.mean(axis=0)

        # Get diagonals and take means.
        diags = Board._get_diags(state)
        diag_means = diags.mean(axis=1)

        # Put slice means together.
        slice_means = [row_means, col_means, diag_means]

        # Check if either player marker is in the means.
        for means in slice_means:
            for marker in [Codes.O_MARK, Codes.X_MARK]:
                if marker in means:
                    return marker
        return None

    def _get_diags(state: np.ndarray) -> np.ndarray:
        """Get board diagonals."""
        inds = np.arange(Board.SIDE_LENGTH)

        # Get diagonals.
        neg_slope_diag = state[inds, inds]
        pos_slope_diag = state[inds, inds[::-1]]

        # Put diagonals together in np array.
        diags = np.stack((neg_slope_diag, pos_slope_diag), axis=0)
        return diags

    def check_tie(state: np.ndarray) -> bool:
        """Check if the board is a tie game. Check after checking win."""
        n_empty = Board._get_n_empty(state)
        return n_empty == 0

    def get_poss_states(state: np.ndarray) -> List[np.ndarray]:
        """Return a list of all possible next states."""
        marker = Board._get_marker(state)

        poss_states = []
        for n_row, row in enumerate(state):
            for n_col, square in enumerate(row):
                # A move is possible if the square is empty.
                if square == Codes.EMPTY:
                    # Create state copy.
                    poss_state = state.copy()

                    poss_state[n_row, n_col] = marker
                    poss_states.append(poss_state)

        return poss_states

    def get_move(curr_state: np.ndarray, desired_state: np.ndarray) -> Move:
        """Get the move to go from the currrent to the desired state."""
        # Get ind of square that is different.
        flat_inds = np.arange(9)
        diff_ind = int(flat_inds[curr_state.ravel() != desired_state.ravel()])

        # Get row and col from flattened ind.
        n_row = diff_ind // 3
        n_col = diff_ind % 3

        # Return move.
        move = Move(n_row, n_col)
        return move


import copy
class Wordlist:
    def __init__(self, words, title ):
        # A List of words
        self.words = words
        # Title for list
        self.title = title
        # Letter statistics - occurance
        self.letterstat = {}
        # Letter statistics - based on position
        self.letterlocstat = {}
        # Score for each word based on statistics
        self.score = {}

    def readwordfile(self, filename):
        try:
            with open(filename, "r") as fh:
                self.words = fh.read().splitlines()
                fh.close()
            return 1
        except IOError:
            print("IOError: ",filename," File does not seem to exist.")
            return fh

    def writewordfile(self, filename):
        try:
            with open(filename, "w") as fh:
                fh.writelines('\n'.join(self.words))
                fh.close()
                print("Writing File:",filename)
        except:
            print("Error on open file for write")

    def makelowercase(self):
        wordlist = []
        for w in self.words:
            wordlist.append(w.lower())
        return wordlist

    def wordsunion(self, wordlist):
        commonlist = []
        for w in self.words:
            for x in wordlist:
                if w == x:
                    commonlist.append(w)
        return commonlist

    def wordssubtract(self, wordlist):
        uniquelist = []
        for w in self.words:
            common = False
            for x in wordlist:
                if w == x:
                    common = True
            if common == False:
                uniquelist.append(w)
        return uniquelist

    def wordsmerge(self, wordlist):
        mergelist = self.words.copy()
        for x in wordlist:
            common = False
            for w in self.words:
                if w == x:
                    common = True
            if common == False:
                mergelist.append(x)
        return mergelist

    def trimwords(self, trimlength):
        trimlist = []
        for w in self.words:
            if len(w) == trimlength:
                trimlist.append(w)
        return trimlist

    def getWordcount(self):
        return len(self.words)

    def getWord(self, index):
        return self.words[index]

    def checkWord(self, word):
        if word in self.words:
            return True
        else:
            return False

    def addword(self, word):
        self.words.append(word)

    def removeword(self, word):
        self.words.remove(word)

    def formatwords(self, numcols, maxwords):
        rtn = '\n'
        rtn += "-------- " + str(self.title)+" "+str(len(self.words))+" words --------"
        if len(self.words)>maxwords:
            rtn += " showing "+str(maxwords)+" words -----"+'\n'
        else:
            rtn += '\n'
        col = 0
        cnt = 0
        for w in self.words:
            cnt = cnt + 1
            rtn += str(w) + " "
            col = col + 1
            if col % numcols == 0:
                rtn += '\n'
            if cnt >= maxwords:
                break
        return rtn

    def letterfrequency(self, cols):
        letters = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
        for letter in letters:
            self.letterlocstat[letter]={}
            self.letterstat[letter] = 0
            for loc in range(cols):
                self.letterlocstat[letter][loc] = 0

        for word in self.words:
            for loc in range(cols):
                for letter in letters:
                    if word[loc] == letter:
                        self.letterstat[letter] += 1
                        self.letterlocstat[letter][loc] +=1

        sorted_letters = sorted(self.letterstat, key=self.letterstat.get, reverse=True)

        rtn = 'LETTER FREQUENCY:\nLetter Total  Postion 1 thru '+str(cols)+'......\n'
        for letter in sorted_letters:
            rtn += "  "+letter.upper()+" "+"{:5.0f}".format(self.letterstat[letter])+"   "
            for loc in range(cols):
                rtn += "{:4.0f}".format(self.letterlocstat[letter][loc]) + " "
            rtn += "\n"
        rtn += "\n"
        return rtn

    def wordscore(self, cols):
        rtn = 'WORD SCORE:\n'
        self.score = {}
        for word in self.words:
            self.score[word] = 0
            for loc in range(cols):
                self.score[word] += self.letterlocstat[word[loc]][loc]

        sorted_score = sorted(self.score, key=self.score.get, reverse=True)

        for word in sorted_score:
            rtn += word + " " + str(self.score[word]) + '\n'
            # print(word, self.score[word])
        rtn += '\n'
        return rtn

    def scorewords_noG(self, greenlist, scoredwordlist, cols):
        # Uses the self score, but apply to another wordlist (all the words)
        rtn = 'ELIMINATION:\n'
        self.score = {}

        for word in self.words:
            self.score[word] = 0
            uniqueletter = set()
            # print(word," ",end="")
            for loc in range(cols):
                letter = word[loc]
                if (letter in greenlist) or (letter in uniqueletter):
                    pass
                else:
                    self.score[word] += scoredwordlist.letterstat[letter]
                    uniqueletter.add(letter)
                    pass

        sorted_noGreen = sorted(self.words, key=self.score.get, reverse=True)

        for word in sorted_noGreen:     # sorted_noGreen scored with original letter scoring:
            rtn += word + " " + str(self.score[word]) + '\n'
            # print(word, self.score[word])
        rtn += '\n'
        return rtn

    def searchresults(self, letterlist, letterdict):

        # Search five letter Common Word List for Words meeting criteria
        # Deprecated: used in console version
        validwords = []
        wordcount = 0
        for w in self.words:
            wordtest = True
            for letter in letterlist:
                # print("letter:", letter)
                loclist = letterdict[letter]

                if loclist[0] == 0:
                    positiontest = True
                    for position in range(5):
                        # print("  position:", position)
                        if w[position - 1] == letter:
                            positiontest = False

                else:
                    positiontest = False
                    for position in loclist:
                        if w[position - 1] == letter:
                            positiontest = True

                if positiontest == False:
                    wordtest = False

            if wordtest == True:
                validwords.append(w)
                wordcount = wordcount + 1

        return validwords

    def criteriaresults(self, inputwordlist, criteria, cols):
        self.words = []
        for w in inputwordlist:
            # print('word:',w, end='')
            wordtest = True
            for letter in criteria:
                lettercount = 0
                crit = criteria[letter]
                hitloc = crit['hit']

                # HITS ( Green )
                # print('hitloc:',hitloc, end='')
                for loc in hitloc:
                    # print(' hit ',loc,' ',end='')
                    if w[loc] != letter.lower():
                        wordtest = False
                        # print('False', end='')
                missloc = crit['miss']

                # MISSES ( Yellow, Black )
                # print('missloc',missloc, end='')
                positiontest = True
                for loc in missloc:
                    # print(' miss ',loc,' ',end='')
                    if w[loc] == letter.lower():
                        positiontest = False
                        # print(' False ', end='')
                if positiontest == False:
                    wordtest = False

                # LETTER COUNT
                for loc in range(cols):
                    if w[loc] == letter.lower():
                        lettercount += 1
                # print('lettercount:',w,' ',letter,": ",lettercount)
                if crit['exact'] == 'Y':
                    if lettercount != crit['tot']:
                        wordtest = False
                        # print('POP exact',crit['tot'])
                else:         # NOT EXACT
                    if lettercount < crit['tot']:
                        wordtest = False
                        # print('POP not exact',crit['tot'])

                # ANY ( RED )
                if crit['any'] == 'Y':
                    if crit['exact'] == " Y":
                        if lettercount != crit['tot']:
                            wordtest = False
                            # print('POP Any exact')
                    else:  # not exact
                        if lettercount < crit['tot']:
                            wordtest = False
                            # print('POP Any')

            if wordtest == True:
                # print("MATCH:",w, lettercount)
                self.words.append(w)
            # print('')

class LetterCell:
    def __init__(self, row, col, letter):
        self.row = row
        self.col = col
        self.letter = letter
        self.color = 'B'

    def nextcolor(self):
        if self.color == 'B':
            self.color = 'Y'
        elif self.color == 'Y':
            self.color = 'G'
        elif self.color == 'G':
            self.color = 'R'
        elif self.color == 'R':
            self.color = 'V'
        else:
            self.color = 'B'

        return self.color

    def setletter(self, letter):
        self.letter = letter

class Criteria:
    def __init__(self, cols):
        # rowlist is representation of the wordle graphical visual fields (i.e. yellow letters, green letters, etc)
        self.rowlist = []         # list(rows) of dict(key=letter) of dict(key=location,value=cell color
        # rowlist gets converted to rowcrit. A more functional coded representation of the rows of visual letters
        self.rowcrit = []         # list(rows) of dict(key=letter) of dict(key=hit,miss,etc.(2 dict and 1 int and 2 chars)
        # rowcrit (list of row criteria) gets merged into a single criteria representing all the rows (mergecrit)
        self.mergecrit = {}       # dict(key=letter) of dict(key=hit,miss,etc.(2 dict and 1 int and 2 chars)
        # example
        # a:[G:[1],Y:[3],total:2,exact:N}
        # b:[G:[],Y:[2,5],total: 1, exact: ######WIP
        # c:[null], 0 only
        self.strcrit = ''   # for printing the criteria
        self.strerror = ''  # error messages from the merged criteria
        self.cols = cols    # number of columns (letters in word, legacy = 5)
        self.greenletters = []  # list of all letters that are green

    def scanwords(self, rows, cols, cell):
        # scans the GUI cells and makes the list of row (rowlist)
        self.rowlist = []

        for r in range(rows):
            # Row data is dict-dict example:
            # { A : { 0:G , 2:Y } , B : { 1:B } }
            # A in pos 0 is green and in pos 2 is yellow. B in pos 1 is black
            letterdict = {}
            for c in range(cols):
                letter = cell[r][c].letter
                color = cell[r][c].color
                if letter in letterdict:
                    letterdict[letter].update({c:color})
                elif letter == " ":
                    pass
                else:
                    letterdict[letter] = {c:color}
            if len(letterdict) > 0:
                self.rowlist.append(letterdict.copy())
            letterdict.clear()
        #print(self.rowlist)

    def printrowlist(self):
        for rowdata in self.rowlist:
            print("ROW:",end='')
            for letterkey in rowdata:
                print("<",letterkey,">  ",end='',sep='')
                tempdict = rowdata[letterkey]
                for loc in tempdict:

                    print(loc,":",tempdict[loc]," ",end='',sep='')
            print()
        print()

    def printrow(self,rowindex):
        print("ROW:",end='')
        rowdata = self.rowlist[rowindex]
        for letterkey in rowdata:
            print("<",letterkey,">  ",end='',sep='')
            tempdict = rowdata[letterkey]
            for loc in tempdict:
                print(loc,":",tempdict[loc]," ",end='',sep='')
        print()

    def makecriteria(self):
        # Make coded list of criteria per row from rowlist
        self.rowcrit = []
        for index, rowdata in enumerate(self.rowlist):

            lettercrit={}   # {'A': {'hit': [0], 'miss': [2], 'tot': 2, 'exact': 'N'}
            # A: { hit:[1] miss:[3] tot:2 exact:N }
            # B: { hit:[]  miss:[25] tot:1 exact:Y }
            # C: { hit:[]  miss:[4]  tot:1 exact:N }
            #print("### Rowdata:",rowdata)
            for letterkey in rowdata:
                if letterkey == " ":
                    lettercrit[letterkey]={}
                else:
                    letterdict = rowdata[letterkey]
                    # letterdict i.e: { 0:G , 1:B, 4:Y }
                    letterhit = []     # list of in this location(lockey) GREEN cell
                    lettermiss = []     # list of miss in this location YELLOW/BLACK
                    lettertot = 0      # total of GREEN and YELLOW cells
                    letterexact = "N"  # exactly total (true) or equal to or more than letter total (false)
                    letterany = "N"    # letter could be in any location
                    for lockey in letterdict:
                        if letterdict[lockey] == "G":
                            letterhit.append(lockey)
                            lettertot += 1
                        elif letterdict[lockey] == "Y":
                            lettermiss.append(lockey)
                            lettertot += 1
                        elif letterdict[lockey] == "B":
                            lettermiss.append(lockey)
                            letterexact = "Y"
                        elif letterdict[lockey] == "R":
                            lettermiss.append(lockey)
                            letterany = "Y"
                        elif letterdict[lockey] == "V":
                            lettermiss.append(lockey)
                        else:   # letterkey[lockey] == (space)
                            pass
                    tempdict={}
                    tempdict['hit']=letterhit
                    tempdict['miss']=lettermiss
                    tempdict['tot']=lettertot
                    tempdict['exact']=letterexact
                    tempdict['any']=letterany
                    lettercrit[letterkey]=tempdict.copy()
            self.rowcrit.append(lettercrit.copy())

    def mergecriteria(self):
        # Merge rowlist criteria (each row in list) into a single criteria (mergecrit)
        self.mergecrit={}
        self.strerror=''
        for rowidx, row in enumerate(self.rowcrit, start=1):
            mergeletters = list(set(list(self.mergecrit)+list(row)))
            # print("merge letters:",mergeletters)
            for letterkey in mergeletters:
                mcrit = d2d(letterkey, self.mergecrit)
                rcrit = d2d(letterkey, row)

                # merge row with existing criteria
                mhit = list(set(list(d2l('hit',mcrit)+d2l('hit',rcrit))))
                mmiss = list(set(list(d2l('miss', mcrit)+d2l('miss', rcrit))))
                mtot = max(d2i('tot',mcrit),d2i('tot',rcrit))
                if d2s('exact',mcrit) == "Y" or d2s('exact',rcrit) == "Y":
                    mexact = 'Y'
                else:
                    mexact = 'N'
                if d2s('any',mcrit) == "Y" or d2s('any',rcrit) == "Y":
                    many = 'Y'
                else:
                    many = 'N'

                # ##### Error checking merge ######
                if ((d2s('exact',mcrit) == "Y" and d2i('tot',rcrit)>d2i('tot',mcrit)) or
                    (d2s('exact',rcrit) == "Y" and d2i('tot',mcrit)>d2i('tot',rcrit))):
                    self.errorcriteria(rowidx,letterkey,"Inconsistent yellow or green cell count with black cell")

                if len( set(d2l('hit',mcrit)) & set(d2l('miss',rcrit)) ) > 0:
                    self.errorcriteria(rowidx, letterkey, "Inconsistent yellow/black versus green cell")
                if len( set(d2l('hit', rcrit)) & set(d2l('miss', mcrit)) ) > 0:
                    self.errorcriteria(rowidx, letterkey, "Inconsistent yellow/black versus green cell")

                # Error check: total misses plus total is greater than number of available cells
                if d2i('tot',rcrit)+len(d2l('miss',rcrit)) > self.cols:
                    self.errorcriteria(rowidx, letterkey, "Not enough cells for condition")

                # write back new merged criteria
                mcrit = {'hit':mhit, 'miss':mmiss, 'tot':mtot, 'exact':mexact, 'any':many}
                self.mergecrit[letterkey] = mcrit
                # print(' Merged:>>>' + str(self.mergecrit))

    def greenletter(self):
        self.greenletters = []
        # a:{hit:[1],miss:[3],total:2,exact:N}
        # b: .....
        for letterkey in self.mergecrit:
            singlelettercrit = self.mergecrit[letterkey]
            hitlist = singlelettercrit["hit"]
            if len(hitlist) != 0:
                # letter is green
                self.greenletters.append(letterkey.lower())

    def printcriteria(self):
        print("CRITERIA: ",self.mergecrit)
        '''
        for letterkey in self.mergecrit:
            letterdict = self.mergecrit[letterkey]
            # print("   ", letterkey," --> ",end="")
            for category in letterdict:
                print("  ", category, ":", letterdict[category], end="")
            print()
        '''

    def textcriteria(self):
        templabel=""
        '''
        for row in self.rowcrit:
            for letterkey in row:
                templabel += letterkey + "  "
                thingdict = row[letterkey]
                for thingkey in thingdict:
                    templabel += thingkey +":"+ str(thingdict[thingkey]) + "\t"
                templabel += "\n"
        templabel += "\n\n"
        '''
        for letterkey in self.mergecrit:
            templabel += letterkey + "  "
            thingdict = self.mergecrit[letterkey]
            for thingkey in thingdict:
                templabel += thingkey + ":" + str(thingdict[thingkey]) + "\t"
            templabel += "\n"
        self.strcrit = templabel

    def errorcriteria(self,row,letter,message):
        self.strerror += 'ERROR: Row:'+str(row)+" Letter:"+str(letter)+" "+message + "\n"

class Search:
    def __init__(self):
        self.rowlist = []

def printcells(rows,cols,cell):
    for rindex in range(rows):
        word = ">>>"
        color = ">>>"
        for cindex in range(cols):
            word += cell[rindex][cindex].letter
            color += cell[rindex][cindex].color
        word += "<<<"
        color += "<<<"
        print(word, color)

def d2d(thekey,thedict):
    rtn = {}
    if thekey in thedict:
        rtn = thedict[thekey]
    return rtn

def d2l(thekey, thedict):
    rtn = []
    if thekey in thedict:
        rtn = thedict[thekey]
    return rtn

def d2i(thekey, thedict):
    rtn = 0
    if thekey in thedict:
        rtn = thedict[thekey]
    return rtn

def d2s(thekey, thedict):
    rtn = 'N'
    if thekey in thedict:
        rtn = thedict[thekey]
    return rtn

# COLOR MAPPING
def cmap(colorcode):
   if colorcode == 'B':
       c = '#000000'
   elif colorcode == 'Y':
       c = '#CDAD00'
   elif colorcode == 'G':
       c = '#228B22'
   elif colorcode == 'R':
       c = '#B22222'
   elif colorcode == 'V':
       c = '#8470FF'  #LightSlateBlue
   else:
       c = '#FF1493'
   return c


# coding=utf-8
import os
from readconfig import ReadConfig

# 读取配置文件
# config_file_path = os.path.split(os.path.realpath(__file__))[0]
# read_config = ReadConfig(os.path.join(config_file_path, 'config.ini'))

read_config = ReadConfig()

# 项目参数设置
prj_path = read_config.getValue('projectConfig', 'project_path')

# 日志路径
log_path = os.path.join(prj_path, 'report', 'log')

# 测试报告路径
report_path = os.path.join(prj_path, 'report', 'testreport')

# 测试数据路径
data_path = os.path.join(prj_path, 'data', 'testdata')


#!/usr/bin/env python3
# -*-coding:UTF-8 -*

"""
The BankAccount Module
======================

It apply IBAN regexes on paste content and warn if above a threshold.

"""

import redis
import time
import redis
import datetime
import re
import string
from itertools import chain

from packages import Paste
from pubsublogger import publisher

from Helper import Process

import signal

class TimeoutException(Exception):
    pass

def timeout_handler(signum, frame):
    raise TimeoutException

signal.signal(signal.SIGALRM, timeout_handler)

_LETTERS_IBAN = chain(enumerate(string.digits + string.ascii_uppercase),
                 enumerate(string.ascii_lowercase, 10))
LETTERS_IBAN = {ord(d): str(i) for i, d in _LETTERS_IBAN}

def iban_number(iban):
    return (iban[4:] + iban[:4]).translate(LETTERS_IBAN)

def is_valid_iban(iban):
    iban_numb = iban_number(iban)
    iban_numb_check = iban_number(iban[:2] + '00' + iban[4:])
    check_digit = '{:0>2}'.format(98 - (int(iban_numb_check) % 97))
    if check_digit == iban[2:4] and int(iban_numb) % 97 == 1:
        # valid iban
        print('valid iban')
        return True
    return False

def check_all_iban(l_iban, paste, filename):
    nb_valid_iban = 0
    for iban in l_iban:
        iban = iban[0]+iban[1]+iban[2]
        iban = ''.join(e for e in iban if e.isalnum())
        #iban = iban.upper()
        res = iban_regex_verify.findall(iban)
        date = datetime.datetime.now().strftime("%Y%m")
        if res:
            print('checking '+iban)
            if is_valid_iban(iban):
                print('------')
                nb_valid_iban = nb_valid_iban + 1
                server_statistics.hincrby('iban_by_country:'+date, iban[0:2], 1)

    if(nb_valid_iban > 0):
        to_print = 'Iban;{};{};{};'.format(paste.p_source, paste.p_date, paste.p_name)
        publisher.warning('{}Checked found {} IBAN;{}'.format(
            to_print, nb_valid_iban, paste.p_rel_path))
        msg = 'infoleak:automatic-detection="iban";{}'.format(filename)
        p.populate_set_out(msg, 'Tags')

        #Send to duplicate
        p.populate_set_out(filename, 'Duplicate')

if __name__ == "__main__":
    publisher.port = 6380
    publisher.channel = "Script"

    config_section = 'BankAccount'

    p = Process(config_section)
    max_execution_time = p.config.getint("BankAccount", "max_execution_time")

    # ARDB #
    server_statistics = redis.StrictRedis(
        host=p.config.get("ARDB_Statistics", "host"),
        port=p.config.getint("ARDB_Statistics", "port"),
        db=p.config.getint("ARDB_Statistics", "db"),
        decode_responses=True)

    publisher.info("BankAccount started")

    message = p.get_from_set()

    #iban_regex = re.compile(r'\b[A-Za-z]{2}[0-9]{2}(?:[ ]?[0-9]{4}){4}(?:[ ]?[0-9]{1,2})?\b')
    iban_regex = re.compile(r'\b([A-Za-z]{2}[ \-]?[0-9]{2})(?=(?:[ \-]?[A-Za-z0-9]){9,30})((?:[ \-]?[A-Za-z0-9]{3,5}){2,6})([ \-]?[A-Za-z0-9]{1,3})\b')
    iban_regex_verify = re.compile(r'^([A-Z]{2})([0-9]{2})([A-Z0-9]{9,30})$')

    while True:

        message = p.get_from_set()

        if message is not None:

            filename = message
            paste = Paste.Paste(filename)
            content = paste.get_p_content()

            signal.alarm(max_execution_time)
            try:
                l_iban = iban_regex.findall(content)
            except TimeoutException:
                 print ("{0} processing timeout".format(paste.p_rel_path))
                 continue
            else:
                signal.alarm(0)

            if(len(l_iban) > 0):
                check_all_iban(l_iban, paste, filename)

        else:
            publisher.debug("Script BankAccount is Idling 10s")
            time.sleep(10)


from introrl.dp_funcs.dp_policy_eval import dp_policy_evaluation
from introrl.black_box_sims.random_walk_1000 import RandomWalk_1000Simulation
from introrl.policy import Policy
from introrl.state_values import StateValues
from introrl.agent_supt.model import Model
from introrl.environments.env_baseline import EnvBaseline
from introrl.utils import pickle_esp

RW = RandomWalk_1000Simulation()

model = Model( RW, build_initial_model=True )
model.collect_transition_data( num_det_calls=100, num_stoic_calls=10000 )
print('Model Built')
# build an EnvBaseline from the Simulation
env = EnvBaseline( s_hash_rowL=RW.s_hash_rowL,
                   x_axis_label=RW.x_axis_label,
                   y_axis_label=RW.y_axis_label )
model.add_all_data_to_an_environment( env )

policy = Policy( environment=env )
policy.intialize_policy_to_equiprobable( env=env )

state_value = StateValues( env )
state_value.init_Vs_to_zero()

dp_policy_evaluation(policy, state_value,
                    do_summ_print=True,
                    max_iter=1000, err_delta=0.0001, gamma=1.0)

pickle_esp.save_to_pickle_file( fname='random_walk_1000_PI_eval', env=env,
                             state_values=state_value, policy=policy)


from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
from django.contrib.sites.models import Site

from backoffice.models import Discipline

def default(request):
    return {
        'disciplines': Discipline.objects.all(),
        'login_form': AuthenticationForm(),
        'path': request.path,
        'request': request,
        'registration_form': UserCreationForm(),
        'site': Site.objects.get_current()
    }


from django.shortcuts import render,redirect
from records.models import Thing,Item, Tsv
from .forms import TsvModelForm
from django.contrib import messages
from datetime import datetime
from dateutil import parser
import csv
from . import literals

def upload_file_view(request):

    form = TsvModelForm(request.POST or None, request.FILES or None)

    stat_one_val = [
        literals.STAT_ONE_CHOICE_ONE,
        literals.STAT_ONE_CHOICE_TWO,
        literals.STAT_ONE_CHOICE_THREE,
        literals.STAT_ONE_CHOICE_FOUR,
        literals.STAT_ONE_CHOICE_FIVE,
        literals.STAT_ONE_CHOICE_NOT_SPECIFIED
        ]

    stat_two_val = [
        literals.STAT_TWO_CHOICE_ONE,
        literals.STAT_TWO_CHOICE_TWO,
        literals.STAT_TWO_CHOICE_THREE,
        literals.STAT_TWO_CHOICE_NOT_SPECIFIED
    ]

    if form.is_valid():

        p = form.save(commit=False)
        form= TsvModelForm()

        with open(p.file_name.path, 'r') as file:
            reader = csv.reader(file, delimiter="\t")

            Thing_list = []
            Item_list = []

            for i,row in enumerate(reader):
                if i == 0:
                    if row[0] != "code" or row[1] != "description" or row[2] != 'date' or row[3] != 'stat_one' or row[4] != 'stat_two' or row[5] != 'name' or row[6] != 'rating' or row[7] != 'score' :
                        messages.error(request,"Table schema invalid")
                        break
                    p.save()
                else:
                    code = row[0]
                    description = row[1]

                    ### date Validation. Also will accept any Date format and convert it into ISO format
                    date = parser.parse(row[2])
                    date = datetime.strftime(date, '%Y-%m-%d')

                    ### Stat_one Validation
                    stat_one = row[3]
                    if stat_one not in stat_one_val:
                        messages.error(request,"Value to Stat_one is not valid in line number: " + str(i+1))
                        continue

                    ### Stat_two Validation
                    stat_two = row[4]
                    if stat_two not in stat_two_val:
                        messages.error(request,'Value of stat_two is not valid in line number: ' + str(i+1))
                        continue
                    name = row[5]
                    score = row[7]

                    ### Rating Validation
                    try:
                        rating = round(float(row[6]),1)
                        if rating < 1.0 or rating > 5.0 :
                            messages.error(request,"Rating not in range in line number: " + str(i+1))
                            continue
                        rating = str(rating)
                    except:
                        messages.error(request,"Rating not number in line number: " + str(i+1))

                    ## Saving the Valid Row in database
                    thingInfo = Thing(
                        code = code,
                        description = description,
                        date = date,
                        stat_one = stat_one,
                        stat_two = stat_two
                    )
                    thingInfo.save()
                    Thing_list.append(thingInfo)

                    itemInfo = Item(
                        thing = thingInfo,
                        name = name,
                        rating = rating,
                        score = score
                    )
                    itemInfo.save()
                    Item_list.append(itemInfo)

        context = {
            'form' : form,
            'things' : Thing_list,
            'Items' : Item_list
        }

        return render(request,'tsv_upload.html', context)

    context = {
        'form' : form
    }

    return render(request,'tsv_upload.html', context)


from blacs.tab_base_classes import Worker
import labscript_utils.h5_lock, h5py
from time import sleep

class _RigolIO():
    def __init__(self, resource_str, access_mode):
        assert access_mode in ['eth', 'usb'], 'access_mode must be one of \'eth\' or \'usb\''
        self.access_mode = access_mode

        if self.access_mode == 'eth':
            import socket

            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.socket.connect((resource_str, 5555))

            self.rigol = self.socket.makefile('brw')
        elif self.access_mode == 'usb':
            import pyvisa

            self.rigol = pyvisa.ResourceManager().open_resource(resource_str)
            self.socket = None

        return

    def write(self, command):
        command = command + '\n'
        if self.socket is not None:
            command = command.encode('ascii')

        self.rigol.write(command)
        if self.socket is not None:
            self.rigol.flush()
            sleep(20e-3) # Rigol gets sad if commands come too fast. 20ms is empirical limit.

        return

    def query(self, command):
        if self.socket is not None:
            self.write(command)

            resp = self.rigol.readline().decode('ascii').strip()
            self.rigol.readline() # Rigol sends blank line afterwards
            return resp
        else:
            return self.rigol.query(command)

    def close(self):
        self.rigol.close()

        if self.socket is not None:
            self.socket.close()
        return

class _RigolDG4162InterfaceChannel(object):
    def __init__(self, channel, io):
        self.channel = channel
        self.io = io

        self.state = 0
        self.mode = None

        self._clear_static()
        self._clear_sweep()

        return

    def _clear_static(self):
        self.freq = None
        self.amplitude = None

        return

    def _clear_sweep(self):
        self.freq_start = None
        self.freq_stop = None
        self.amplitude = None
        self.time = None
        self.time_hold_start = None
        self.time_hold_stop = None
        self.time_return = None
        self.spacing = None
        self.steps = None
        self.trigger_slope = None
        self.trigger_source = None
        self.trigger_out = None

        return

    def get_state(self):
        return self.io.query(':OUTP{}:STAT?'.format(self.channel))

    def get_mode(self):
        return self.mode

    def output_on(self, fresh=False):
        if self.state == 0 or not fresh:
            self.io.write(':OUTP{:d}:STAT ON'.format(self.channel))
        return

    def output_off(self, fresh=False):
        if self.state == 1 or not fresh:
            self.io.write(':OUTP{:d}:STAT OFF'.format(self.channel))
        return

    def get_static_freq(self):
        return self.io.query(':SOUR{}:FREQ?'.format(self.channel))

    def get_static_amplitude(self):
        return self.io.query(':SOUR{}:VOLT?'.format(self.channel))

    def static(self, freq, amplitude, fresh):
        if self.mode != 'static' or not fresh:
            self.io.write(':SOUR{}:SWE:STAT OFF'.format(self.channel))
            self.io.write(':OUTP{}:LOAD 50'.format(self.channel))
            self.io.write(':SOUR{}:FUNC:SHAP SIN'.format(self.channel))
            fresh = False

        if self.freq != freq or not fresh:
            self.io.write(':SOUR{}:FREQ {}'.format(self.channel, freq))
        if self.amplitude != amplitude or not fresh:
            self.io.write(':SOUR{}:VOLT:UNIT DBM'.format(self.channel))
            self.io.write(':SOUR{}:VOLT {}'.format(self.channel, amplitude))
            self.io.write(':SOUR{}:VOLT:OFFS 0'.format(self.channel))

        self._clear_sweep()
        self.mode = 'static'
        self.freq = freq
        self.amplitude = amplitude

        return

    def get_sweep_freq_start(self):
        return self.io.query(':SOUR{}:FREQ:STAR?'.format(self.channel))

    def get_sweep_freq_stop(self):
        return self.io.query(':SOUR{}:FREQ:STOP?'.format(self.channel))

    def get_sweep_amplitude(self):
        return self.io.query(':SOUR{}:VOLT?'.format(self.channel))

    def get_sweep_time(self):
        return self.io.query(':SOUR{}:SWE:TIME?'.format(self.channel))

    def get_sweep_time_hold_start(self):
        return self.io.query(':SOUR{}:SWE:HTIM:STAR?'.format(self.channel))

    def get_sweep_time_hold_stop(self):
        return self.io.query(':SOUR{}:SWE:HTIM:STOP?'.format(self.channel))

    def get_sweep_time_return(self):
        return self.io.query(':SOUR{}:SWE:HTIM:RTIM?'.format(self.channel))

    def get_sweep_spacing(self):
        return self.io.query(':SOUR{}:SWE:SPAC?'.format(self.channel))

    def get_sweep_trigger_slope(self):
        return self.io.query(':SOUR{}:SWE:TRIG:SLOP?'.format(self.channel))

    def get_sweep_trigger_source(self):
        return self.io.query(':SOUR{}:SWE:TRIG:SOUR?'.format(self.channel))

    def get_sweep_trigger_out(self):
        return self.io.query(':SOUR{}:SWE:TRIG:TRIGO?'.format(self.channel))

    def get_sweep_steps(self):
        return self.io.query(':SOUR{}:SWE:STEP?'.format(self.channel))

    def sweep(self, freq_start, freq_stop, amplitude,
              time, time_hold_start, time_hold_stop, time_return, spacing,
              trigger_slope, trigger_source, trigger_out, steps, fresh):
        assert spacing in ['LIN', 'LOG', 'STE'], \
            'spacing must be LINear, LOGarithmic, or STEp'
        assert trigger_slope in ['POS', 'NEG'], \
            'trigger_slope must be POSitive or NEGative'
        assert trigger_source in ['EXT', 'INT', 'MAN'], \
            'trigger_source must be EXTernal, INTernal, or MANual'
        assert trigger_out in ['OFF', 'POS', 'NEG'], \
            'trigger_out must be OFF, POSitive or NEGative'

        if time_hold_start == 0:
            time_hold_start = 'MIN'
        if time_hold_stop == 0:
            time_hold_stop = 'MIN'
        if time_return == 0:
            time_return = 'MIN'
        if time == 0:
            time = 'MIN'

        if self.mode != 'sweep' or not fresh:
            self.io.write(':OUTP{}:LOAD 50'.format(self.channel))
            self.io.write(':SOUR{}:FUNC:SHAP SIN'.format(self.channel))
            self.io.write(':SOUR{}:SWE:STAT ON'.format(self.channel))
            fresh = False
        if self.freq_start != freq_start or not fresh:
            self.io.write(':SOUR{}:FREQ:STAR {}'.format(self.channel, freq_start))
        if self.freq_stop != freq_stop or not fresh:
            self.io.write(':SOUR{}:FREQ:STOP {}'.format(self.channel, freq_stop))
        if self.amplitude != amplitude or not fresh:
            self.io.write(':SOUR{}:VOLT:UNIT DBM'.format(self.channel))
            self.io.write(':SOUR{}:VOLT {}'.format(self.channel, amplitude))
            self.io.write(':SOUR{}:VOLT:OFFS 0'.format(self.channel))
        if self.time_hold_start != time_hold_start or not fresh:
            self.io.write(':SOUR{}:SWE:HTIM:STAR {}'.format(self.channel, time_hold_start))
        if self.time_hold_stop != time_hold_stop or not fresh:
            self.io.write(':SOUR{}:SWE:HTIM:STOP {}'.format(self.channel, time_hold_stop))
        if self.time_return != time_return or not fresh:
            self.io.write(':SOUR{}:SWE:HTIM:RTIM {}'.format(self.channel, time_return))
        if self.spacing != spacing or not fresh:
            self.io.write(':SOUR{}:SWE:SPAC '.format(self.channel) + spacing)
        if spacing == 'STE' and (self.steps != steps or not fresh):
            self.io.write(':SOUR{}:SWE:STEP {}'.format(self.channel, steps))
        if self.time != time or not fresh:
            self.io.write(':SOUR{}:SWE:TIME {}'.format(self.channel, time))
        if self.trigger_slope != trigger_slope or not fresh:
            self.io.write(':SOUR{}:SWE:TRIG:SLOP '.format(self.channel) + trigger_slope)
        if self.trigger_source != trigger_source or not fresh:
            self.io.write(':SOUR{}:SWE:TRIG:SOUR '.format(self.channel) + trigger_source)
        if self.trigger_out != trigger_out or not fresh:
            self.io.write(':SOUR{}:SWE:TRIG:TRIGO '.format(self.channel) + trigger_out)

        if trigger_source == 'MAN': # Trigger manual sweep now
            self.io.write(':SOUR{}:SWE:TRIG:IMM'.format(self.channel))

        self._clear_static()
        self.mode = 'sweep'
        self.freq_start = freq_start
        self.freq_stop = freq_stop
        self.amplitude = amplitude
        self.time = time
        self.time_hold_start = time_hold_start
        self.time_hold_stop = time_hold_stop
        self.time_return = time_return
        self.spacing = spacing
        self.trigger_slope = trigger_slope
        self.trigger_source = trigger_source
        self.trigger_out = trigger_out
        self.steps = steps

        return

class RigolDG4162Interface(object):
    def __init__(self, resource_str, access_mode):
        self.access_mode = access_mode
        self.io = _RigolIO(resource_str, access_mode)

        self.channels = [_RigolDG4162InterfaceChannel(1, self.io),
                         _RigolDG4162InterfaceChannel(2, self.io)]

        return

    def output_on(self, channel, fresh=False):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].output_on(fresh)

    def output_off(self, channel, fresh=False):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].output_off(fresh)

    def get_state(self, channel):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].get_state()

    def get_mode(self, channel):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].get_mode()

    def get_static_freq(self, channel):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].get_static_freq()

    def get_static_amplitude(self, channel):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].get_static_amplitude()

    def static(self, channel, freq=0, amplitude=0, fresh=False):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].static(freq, amplitude, fresh)

    def get_sweep_freq_start(self, channel):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].get_sweep_freq_start()

    def get_sweep_freq_stop(self, channel):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].get_sweep_freq_stop()

    def get_sweep_amplitude(self, channel):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].get_sweep_amplitude()

    def get_sweep_time(self, channel):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].get_sweep_time()

    def get_sweep_time_hold_start(self, channel):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].get_sweep_time_hold_start()

    def get_sweep_time_hold_stop(self, channel):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].get_sweep_time_hold_stop()

    def get_sweep_time_return(self, channel):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].get_sweep_time_return()

    def get_sweep_spacing(self, channel):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].get_sweep_spacing()

    def get_sweep_trigger_slope(self, channel):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].get_sweep_trigger_slope()

    def get_sweep_trigger_source(self, channel):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].get_sweep_trigger_source()

    def get_sweep_trigger_out(self, channel):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].get_sweep_trigger_out()

    def get_sweep_steps(self, channel):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].get_sweep_steps()

    def sweep(self, channel, freq_start=0, freq_stop=0, amplitude=0,
              time=0, time_hold_start=0, time_hold_stop=0, time_return=0, spacing='LIN',
              trigger_slope='POS', trigger_source='EXT', trigger_out='OFF', steps=0,
              fresh=False):
        assert channel in [1, 2], 'channel should be 1 or 2'
        return self.channels[channel-1].sweep(freq_start, freq_stop, amplitude, time,
                                              time_hold_start, time_hold_stop,
                                              time_return, spacing,
                                              trigger_slope, trigger_source,
                                              trigger_out, steps, fresh)

    def write(self, command):
        return self.io.write(command)

    def query(self, command):
        return self.io.query(command)

    def close(self):
        return self.io.close()

class Rigol4162Worker(Worker):
    def init(self):
        self.rigol = RigolDG4162Interface(self.resource_str, self.access_mode)

    def check_remote_values(self):
        remove_values = {}
        for channel in [1, 2]:
            state = self.rigol.get_state(channel)
            if state == 'OFF':
                remote_values['channel {:d}'.format(channel)] = {'state': 0}
                continue

            mode = self.rigol.get_mode(channel)

            if mode == 'static':
                cv = {'state': 1, 'mode': 'static',
                      'freq': self.rigol.get_static_freq(channel),
                      'amplitude': self.rigol.get_static_amplitude(channel),}
                remote_values['channel {:d}'.format(channel)] = cv
            elif mode == 'sweep':
                cv = {'state': 1, 'mode': 'sweep',
                      'freq_start': self.rigol.get_sweep_freq_start(channel),
                      'freq_stop': self.rigol.get_sweep_freq_stop(channel),
                      'amplitude': self.rigol.get_sweep_amplitude(channel),
                      'time': self.rigol.get_sweep_time(channel),
                      'time_hold_start': self.rigol.get_sweep_time_hold_start(channel),
                      'time_hold_stop': self.rigol.get_sweep_time_hold_stop(channel),
                      'time_return': self.rigol.get_sweep_time_return(channel),
                      'spacing': self.rigol.get_sweep_spacing(channel),
                      'steps': self.rigol.get_sweep_steps(channel),
                      'trigger_slope': self.rigol.get_sweep_trigger_slope(channel),
                      'trigger_source': self.rigol.get_sweep_trigger_source(channel),
                      'trigger_out': self.rigol.get_sweep_trigger_out(channel)}
                remote_values['channel {:d}'.format(channel)] = cv
            else:
                remote_values['channel {:d}'.format(channel)] = {'state': 0}

        return remote_values

    def program_manual(self, values):
        for channel in [1, 2]:
            key = 'channel {:d}'.format(channel)
            if key in values.keys():
                if values[key] is None:
                    values[key] = {'state': False}
            setting = values[key]

            if not setting['state']:
                self.rigol.output_off(channel)
                continue

            if setting['mode'] == 'static':
                self.rigol.static(channel, setting['freq'], setting['amplitude'])
            elif setting['mode'] == 'sweep':
                self.rigol.sweep(channel, setting['freq'], setting['freq_stop'],
                                 setting['amplitude'], setting['time'],
                                 setting['time_hold_start'], setting['time_hold_stop'],
                                 setting['time_return'], setting['spacing'],
                                 setting['trigger_slope'], setting['trigger_source'],
                                 setting['trigger_out'], setting['steps'])
            else:
                print('Invalid mode')

            self.rigol.output_on(channel)
        return

    def _parse_channel_dataset(self, dataset):
        state = dataset['state'][0]
        if not state:
            return {'state': 0}

        mode = dataset['mode'][0].decode()
        if mode == 'static':
            return {'state': 1, 'mode': 'static',
                    'freq': dataset['freq'][0], 'amplitude': dataset['amplitude'][0]}
        elif mode == 'sweep':
            return {'state': 1, 'mode': 'sweep',
                    'freq': dataset['freq'][0],
                    'freq_stop': dataset['freq_stop'][0],
                    'amplitude': dataset['amplitude'][0],
                    'time': dataset['time'][0],
                    'time_hold_start': dataset['time_hold_start'][0],
                    'time_hold_stop': dataset['time_hold_stop'][0],
                    'time_return': dataset['time_return'][0],
                    'spacing': dataset['spacing'][0].decode(),
                    'steps': dataset['steps'][0],
                    'trigger_slope': dataset['trigger_slope'][0].decode(),
                    'trigger_source': dataset['trigger_source'][0].decode(),
                    'trigger_out': dataset['trigger_out'][0].decode()}
        else:
            return {'state': 0}

    def transition_to_buffered(self, device_name, h5file, initial_values, fresh):
        with h5py.File(h5file, 'r') as hdf5_file:
            group = hdf5_file['/devices/' + device_name]
            values = {}
            if 'channel 1' in group:
                values['channel 1'] = self._parse_channel_dataset(group['channel 1'])
            else:
                values['channel 1'] = {'state': False}
            if 'channel 2' in group:
                values['channel 2'] = self._parse_channel_dataset(group['channel 2'])
            else:
                values['channel 2'] = {'state': False}
        self.program_manual(values)
        return {}

    def transition_to_manual(self):
        return True

    def abort_buffered(self):
        return True

    def abort_transition_to_buffered(self):
        return True

    def shutdown(self):
        self.rigol.close()


import numpy
from numpy.lib import math

class DataSeparator:
    @staticmethod
    def separateDate(data):
        print('Separating dates...')
        data['Year'] = data['Dates'].dt.year
        data['Day'] = data['Dates'].dt.day
        data['Month'] = data['Dates'].dt.month
        data['DayOfWeek'] = data['Dates'].dt.weekday
        data['Hour'] = data['Dates'].dt.hour
        data['Minute'] = data['Dates'].dt.minute
        data.drop(columns=['Dates'], inplace=True)
        print('Separated dates!')

    @staticmethod
    def extractAddressInfo(data):
        print('Extracting address info...')
        data['Block'] = data['Address'].str.contains('block', case=False)
        data.drop(columns=['Address'], inplace=True)
        print('Extracted address info!')

    @staticmethod
    def dropUselessColumns(data):
        print('Dropping useless columns...')
        data.drop(columns=['Descript', 'Resolution'], inplace=True)
        print('Dropped useless columns!')