import datetime
import os

from django.contrib.auth.models import User
from django.core.validators import MaxValueValidator
from django.db import models
from django.dispatch import receiver
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

from lib.functions.custom_functions import truncate
from lib.functions.custom_functions import fiscal_year
from lib.templatetags.custom_filters import nz
from shared_models import models as shared_models
from masterlist import models as ml_models
from sar_search import models as sar_models

class Status(models.Model):
    name = models.CharField(max_length=255, verbose_name=_("name (English)"))
    nom = models.CharField(max_length=255, blank=True, null=True, verbose_name=_("name (French)"))
    color = models.CharField(max_length=15, blank=True, null=True)
    old_id = models.IntegerField(blank=True, null=True)
    description_text = models.CharField(max_length=250, blank=True, null=True)

    def __str__(self):
        # check to see if a french value is given
        if getattr(self, str(_("name"))):
            return "{}".format(getattr(self, str(_("name"))))
        # if there is no translated term, just pull from the english field
        else:
            return "{}".format(self.name)

    class Meta:
        ordering = [_('name'), ]

class Program(models.Model):
    name = models.CharField(max_length=255, verbose_name=_("name (English)"))
    nom = models.CharField(max_length=255, blank=True, null=True, verbose_name=_("name (French)"))
    abbrev_eng = models.CharField(max_length=255, blank=True, null=True, verbose_name=_("abbreviation (French)"))
    abbrev_fre = models.CharField(max_length=255, blank=True, null=True, verbose_name=_("abbreviation (French)"))

    def __str__(self):
        # # check to see if a french value is given
        # if getattr(self, str(_("name"))):
        #     return "{}".format(getattr(self, str(_("name"))))
        # # if there is no translated term, just pull from the english field
        # else:
        #     return "{}".format(self.name)
        return "{} ({})".format(self.name, self.abbrev_eng)

    @property
    def full_eng(self):
        return "{} ({})".format(self.name, self.abbrev_eng)

    @property
    def full_fre(self):
        return "{} ({})".format(self.nom, self.abbrev_fre)

    class Meta:
        ordering = [_('name'), ]

class RiskAssessmentScore(models.Model):
    name = models.CharField(max_length=255, verbose_name=_("name (English)"))
    nom = models.CharField(max_length=255, blank=True, null=True, verbose_name=_("name (French)"))

    def __str__(self):
        # check to see if a french value is given
        if getattr(self, str(_("name"))):
            return "{}".format(getattr(self, str(_("name"))))
        # if there is no translated term, just pull from the english field
        else:
            return "{}".format(self.name)

    class Meta:
        ordering = [_('name'), ]

class InitiationType(models.Model):
    name = models.CharField(max_length=255, verbose_name=_("name (English)"))
    nom = models.CharField(max_length=255, blank=True, null=True, verbose_name=_("name (French)"))

    def __str__(self):
        # check to see if a french value is given
        if getattr(self, str(_("name"))):
            return "{}".format(getattr(self, str(_("name"))))
        # if there is no translated term, just pull from the english field
        else:
            return "{}".format(self.name)

    class Meta:
        ordering = [_('name'), ]

class PriorityAreaOrThreat(models.Model):
    # choices for type
    THREAT = 1
    PRIORITY = 2
    SPECIES = 3
    TYPE_CHOICES = (
        (THREAT, _("Threat")),
        (PRIORITY, _("Priority area")),
        (SPECIES, _("Priority species")),
    )
    name = models.CharField(max_length=255, verbose_name=_("name (English)"))
    nom = models.CharField(max_length=255, blank=True, null=True, verbose_name=_("name (French)"))
    type = models.IntegerField(blank=True, null=True, choices=TYPE_CHOICES)

    def __str__(self):
        # check to see if a french value is given
        if getattr(self, str(_("name"))):
            return "{} ({})".format(
                getattr(self, str(_("name"))),
                self.get_type_display(),
            )
        # if there is no translated term, just pull from the english field
        else:
            return "{} ({})".format(self.name, self.get_type_display())

    class Meta:
        ordering = ['type', _('name'), ]

def draft_ca_file_directory_path(instance, filename):
    # file will be uploaded to MEDIA_ROOT/entry_<id>/<filename>
    suffix = filename.split(".")[1]
    return 'spot/{0}/{0}_draft_contribution_agreement.{1}'.format(instance.id, suffix)

class Activity(models.Model):
    #choices for habitat
    FW = 1
    MAR =2
    HABITAT_CHOICES = (
        (FW, _("Freshwater")),
        (MAR, _("Marine")),
    )

    program = models.ForeignKey(Program, on_delete=models.DO_NOTHING, related_name="activities", verbose_name=_("funding program"),
                                blank=True, null=True)
    name = models.CharField(max_length=255, verbose_name=_("name (English)"))
    nom = models.CharField(max_length=255, blank=True, null=True, verbose_name=_("name (French)"))
    habitat = models.IntegerField(blank=True, null=True, choices=HABITAT_CHOICES)
    category_eng = models.CharField(max_length=1000, verbose_name=_("category/type (English)"))
    category_fre = models.CharField(max_length=1000, blank=True, null=True, verbose_name=_("category/type (French)"))

    def __str__(self):
        # check to see if a french value is given
        my_str = "{}".format(getattr(self, str(_("category_eng"))))

        if self.habitat:
            my_str += " ({}) - ".format(self.get_habitat_display())
        else:
            my_str += " - "

        my_str +=  "{}".format(getattr(self, str(_("name"))))
        return my_str

    class Meta:
        ordering = ["program", _('category_eng'), _('name'), ]

class DrainageBasin(models.Model):
    name = models.CharField(max_length=255, verbose_name=_("name (English)"))
    nom = models.CharField(max_length=255, blank=True, null=True, verbose_name=_("name (French)"))

    def __str__(self):
        # check to see if a french value is given
        if getattr(self, str(_("name"))):
            return "{}".format(getattr(self, str(_("name"))))
        # if there is no translated term, just pull from the english field
        else:
            return "{}".format(self.name)

    class Meta:
        ordering = [_('name'), ]

class Watershed(models.Model):
    name = models.CharField(max_length=255, verbose_name=_("name (English)"))
    nom = models.CharField(max_length=255, blank=True, null=True, verbose_name=_("name (French)"))
    province = models.ForeignKey(shared_models.Province, on_delete=models.DO_NOTHING, related_name="watersheds")
    drainage_basin = models.ForeignKey(DrainageBasin, on_delete=models.DO_NOTHING, related_name="watersheds")
    notes = models.CharField(max_length=1000, blank=True, null=True, verbose_name=_("notes"))

    def __str__(self):
        # check to see if a french value is given
        if getattr(self, str(_("name"))):
            return "{}, {} ({})".format(getattr(self, str(_("name"))), self.province.tabbrev, self.drainage_basin)
        # if there is no translated term, just pull from the english field
        else:
            return "{}, {} ({})".format(self.name, self.province.tabbrev, self.drainage_basin)

    class Meta:
        ordering = [_('name'), ]

class Project(models.Model):
    path_number = models.CharField(max_length=50, blank=True, null=True, verbose_name=_("DFO PATH #"))
    program_reference_number = models.CharField(max_length=50, blank=True, null=True)
    organization = models.ForeignKey(ml_models.Organization, on_delete=models.DO_NOTHING, related_name="projects")
    program = models.ForeignKey(Program, on_delete=models.DO_NOTHING, related_name="projects", verbose_name=_("funding program"))
    status = models.ForeignKey(Status, on_delete=models.DO_NOTHING, related_name="projects", default=1, verbose_name=_("project status"))
    regions = models.ManyToManyField(shared_models.Region, default=1, verbose_name=_("DFO regions"))
    start_year = models.ForeignKey(shared_models.FiscalYear, on_delete=models.DO_NOTHING, related_name="gc_projects",
                                   default=fiscal_year(sap_style=True, next=True))
    project_length = models.IntegerField(blank=True, null=True)
    date_completed = models.DateTimeField(blank=True, null=True)
    summary = models.TextField(blank=True, null=True, verbose_name=_("summary"))
    old_id = models.IntegerField(blank=True, null=True)
    eccc_id = models.CharField(max_length=50, blank=True, null=True)

    ## Initiation
    language = models.ForeignKey(shared_models.Language, on_delete=models.DO_NOTHING, related_name="projects",
                                 verbose_name=_("project language"))
    title = models.TextField()
    title_abbrev = models.CharField(max_length=500, blank=True, null=True, verbose_name=_("title abbreviation"))
    initiation_date = models.DateTimeField(blank=True, null=True, default=timezone.now)
    initiation_type = models.ForeignKey(InitiationType, on_delete=models.DO_NOTHING, related_name="projects", blank=True, null=True,
                                        verbose_name=_("type of initiation"))
    priority_area_or_threats = models.ManyToManyField(PriorityAreaOrThreat, related_name="projects", blank=True,
                                                      verbose_name=_("priority areas or threats"))
    initiation_acknowledgement_sent = models.DateTimeField(blank=True, null=True, verbose_name=_("acknowledgement email sent"))
    requested_funding_y1 = models.FloatField(blank=True, null=True, verbose_name=_("requested funding (year 1)"))
    requested_funding_y2 = models.FloatField(blank=True, null=True, verbose_name=_("requested funding (year 2)"))
    requested_funding_y3 = models.FloatField(blank=True, null=True, verbose_name=_("requested funding (year 3)"))
    requested_funding_y4 = models.FloatField(blank=True, null=True, verbose_name=_("requested funding (year 4)"))
    requested_funding_y5 = models.FloatField(blank=True, null=True, verbose_name=_("requested funding (year 5)"))
    overview = models.TextField(blank=True, null=True, verbose_name=_("project overview"))

    ## Regional Review
    regional_score = models.FloatField(blank=True, null=True, verbose_name=_("regional score"))
    rank = models.IntegerField(blank=True, null=True, verbose_name=_("project rank"))
    application_submission_date = models.DateTimeField(blank=True, null=True, verbose_name=_("Date/time of application submission"))
    submission_accepted = models.NullBooleanField(verbose_name=_("was the submission accepted?"))
    notes = models.TextField(blank=True, null=True, verbose_name=_("project notes"))
    recommended_funding_y1 = models.FloatField(blank=True, null=True, verbose_name=_("recommended funding amount - Year 1"))
    recommended_funding_y2 = models.FloatField(blank=True, null=True, verbose_name=_("recommended funding amount - Year 2"))
    recommended_funding_y3 = models.FloatField(blank=True, null=True, verbose_name=_("recommended funding amount - Year 3"))
    recommended_funding_y4 = models.FloatField(blank=True, null=True, verbose_name=_("recommended funding amount - Year 4"))
    recommended_funding_y5 = models.FloatField(blank=True, null=True, verbose_name=_("recommended funding amount - Year 5"))
    recommended_overprogramming = models.FloatField(blank=True, null=True, verbose_name=_("recommended amount for over-programming"))
    regrets_or_op_letter_sent_date = models.DateTimeField(blank=True, null=True,
                                                          verbose_name=_("client notification sent (OP or Regrets only)"))

    ## Negotiations
    risk_assessment_score = models.ForeignKey(RiskAssessmentScore, on_delete=models.DO_NOTHING, related_name="projects", blank=True,
                                              null=True)
    negotiations_workplan_completion_date = models.DateTimeField(blank=True, null=True, verbose_name=_("negotiation workplan complete"))
    negotiations_financials_completion_date = models.DateTimeField(blank=True, null=True, verbose_name=_("negotiation financials complete"))
    negotiation_letter_sent = models.DateTimeField(blank=True, null=True, verbose_name=_("negotiation letter sent to client"))

    ## CA Assembly
    schedule_5_complete = models.DateTimeField(blank=True, null=True, verbose_name=_("schedule 5 is complete"))
    advance_payment = models.BooleanField(default=True, verbose_name=_("will this project receive an advance payment?"))
    draft_ca_sent_to_proponent = models.DateTimeField(blank=True, null=True, verbose_name=_("draft CA sent to client"))
    draft_ca_proponent_approved = models.DateTimeField(blank=True, null=True, verbose_name=_("draft CA approved by client"))
    draft_ca_ready = models.DateTimeField(blank=True, null=True, verbose_name=_("draft CA ready"))
    ## CA Checklist stuff
    draft_ca_sent_to_manager = models.DateTimeField(blank=True, null=True, verbose_name=_("draft CA sent to manager"))
    draft_ca_manager_approved = models.DateTimeField(blank=True, null=True, verbose_name=_("draft CA approved by manager"))
    draft_ca_sent_to_nhq = models.DateTimeField(blank=True, null=True, verbose_name=_("draft CA sent to NHQ"))
    aip_received = models.DateTimeField(blank=True, null=True, verbose_name=_("approve-in-principal (AIP) received"))
    final_ca_received = models.DateTimeField(blank=True, null=True, verbose_name=_("final CA received from NHQ"))
    final_ca_sent_to_proponent = models.DateTimeField(blank=True, null=True, verbose_name=_("final CA sent to client"))
    final_ca_proponent_signed = models.DateTimeField(blank=True, null=True, verbose_name=_("final CA signed by client"))
    final_ca_sent_to_nhq = models.DateTimeField(blank=True, null=True, verbose_name=_("final CA sent to HNQ"))
    advance_payment_sent_to_nhq = models.DateTimeField(blank=True, null=True, verbose_name=_("advance payment sent to NHQ"))
    final_ca_nhq_signed = models.DateTimeField(blank=True, null=True, verbose_name=_("final CA signed by NHQ"))

    # meta
    date_last_modified = models.DateTimeField(blank=True, null=True, default=timezone.now, verbose_name=_("date last modified"))
    last_modified_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name=_("last modified by"),
                                         related_name="gc_projects")
    people = models.ManyToManyField(ml_models.Person, through="ProjectPerson", blank=True)
    activities = models.ManyToManyField(Activity, blank=True, verbose_name=_("activities"))
    spp = models.ManyToManyField(sar_models.Species, blank=True, verbose_name=_("species"))
    watersheds = models.ManyToManyField(Watershed, blank=True, verbose_name=_("watersheds"))

    def __str__(self):
        return "{} ({})".format(truncate(self.title, 50), self.organization.abbrev)

    def save(self, *args, **kwargs):
        self.date_last_modified = timezone.now()

        # determine status
        self.status_id = determine_project_status(self)

        # determine length
        self.project_length = determine_project_length(self, self.status_id)

        return super().save(*args, **kwargs)

    class Meta:
        ordering = ["-start_year", "program"]

    @property
    def total_requested_funding(self):
        return sum([
            nz(self.requested_funding_y1, 0),
            nz(self.requested_funding_y2, 0),
            nz(self.requested_funding_y3, 0),
            nz(self.requested_funding_y4, 0),
            nz(self.requested_funding_y5, 0),
        ])

    @property
    def total_recommended_funding(self):
        return sum([
            nz(self.recommended_funding_y1, 0),
            nz(self.recommended_funding_y2, 0),
            nz(self.recommended_funding_y3, 0),
            nz(self.recommended_funding_y4, 0),
            nz(self.recommended_funding_y5, 0),
        ])

    @property
    def total_project_funding(self):
        if self.years:
            return sum([nz(f.annual_funding, 0) for f in self.years.all()])
        else:
            return 0

    @property
    def negotiation_completion_date(self):
        """ this will be the max of negotiations_workplan_completion_date and negotiations_financials_completion_date"""
        return max(self.negotiations_workplan_completion_date, self.negotiations_financials_completion_date)

    @property
    def end_year(self):
        return self.years.order_by("fiscal_year").last().fiscal_year.full

    # PEOPLE
    @property
    def pp(self):
        return self.project_people.get(role=1).person

    @property
    def gc_officer(self):
        return self.project_people.get(role=7).person

    # FILES
    @property
    def application_file(self):
        return File.objects.get(project=self, file_type_id=6)

    @property
    def project_evaluation_file(self):
        return File.objects.get(project=self, file_type_id=8)

    @property
    def risk_assessment_file(self):
        return File.objects.get(project=self, file_type_id=4)

    @property
    def draft_ca_file(self):
        return File.objects.get(project=self, file_type_id=1)

    @property
    def fully_signed_ca_file(self):
        return File.objects.get(project=self, file_type_id=2)

class Role(models.Model):
    name = models.CharField(max_length=255, verbose_name=_("name (English)"))
    nom = models.CharField(max_length=255, blank=True, null=True, verbose_name=_("Name (French)"))
    order = models.IntegerField(blank=True, null=True)

    def __str__(self):
        # check to see if a french value is given
        if getattr(self, str(_("name"))):
            return "{}".format(getattr(self, str(_("name"))))
        # if there is no translated term, just pull from the english field
        else:
            return "{}".format(self.name)

    class Meta:
        ordering = [_('order'), ]

class ProjectPerson(models.Model):
    project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name="project_people")
    person = models.ForeignKey(ml_models.Person, on_delete=models.DO_NOTHING, related_name="project_people")
    role = models.ForeignKey(Role, on_delete=models.DO_NOTHING, related_name="project_people")

    # meta
    date_last_modified = models.DateTimeField(blank=True, null=True, default=timezone.now, verbose_name=_("date last modified"))
    last_modified_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name=_("last modified by"))

    def save(self, *args, **kwargs):
        self.date_last_modified = timezone.now()
        return super().save(*args, **kwargs)

    class Meta:
        unique_together = ['project', 'person', 'role']
        ordering = ['project', 'role', 'person']

class ContributionAgreementChecklist(models.Model):
    project = models.OneToOneField(Project, on_delete=models.CASCADE, related_name="ca_checklist")
    date_assessed = models.DateTimeField(blank=True, null=True, default=timezone.now)
    risk_assessment_complete = models.NullBooleanField(verbose_name=_("The risk assessment has been completed/approved and posted to PATH"))
    correct_clause_selected = models.NullBooleanField(
        verbose_name=_("The clauses selected in the CA reflect the risk level and contribution amount"))
    formatting_correct = models.NullBooleanField(verbose_name=_("There are no hanging/orphan lines/titles"))
    amounts_correct = models.NullBooleanField(verbose_name=_(
        "The annual contribution amount(s) (3.1) match(es) the budget in Schedule 5 and do(es) not exceed the amount(s) approved by the Minister"))
    clear_language = models.NullBooleanField(
        verbose_name=_("Schedule 5: Language is clear, concise and can be generally understood by someone who is not a specialist"))
    acronyms_defined = models.NullBooleanField(verbose_name=_("Schedule 5: Acronyms are defined upon first use"))
    activities_elibigle = models.NullBooleanField(verbose_name=_("Schedule 5: All Activities/tasks are eligible"))
    detail_commensurate_with_budget = models.NullBooleanField(
        verbose_name=_("Schedule 5: The level of detail for each Activity (i.e., task description) is commensurate with its budget"))
    realistic_timeframe = models.NullBooleanField(
        verbose_name=_("Schedule 5: Each Activity can be reasonably expected to be completed within its accorded timeframe"))
    key_tasks_outlined = models.NullBooleanField(
        verbose_name=_("Schedule 5: All key tasks required to be undertaken for each Activity to be achieved are outlined"))
    deliverables = models.NullBooleanField(verbose_name=_(
        "Schedule 5: All Activities/tasks have associated deliverables that will demonstrate that the former were completed as planned and as budgeted"))
    project_budgets_adds_up = models.NullBooleanField(
        verbose_name=_("Schedule 5: The sum of all individual project Activity budgets adds up to the agreement total"))
    sufficient_budget_detail = models.NullBooleanField(
        verbose_name=_("Schedule 5: Sufficient budget details have been provided to confirm that the costs are eligible and reasonable"))
    expenses_eligible = models.NullBooleanField(verbose_name=_("Schedule 5: All expenses are eligible"))
    reasonable_costs = models.NullBooleanField(verbose_name=_("Schedule 5: All costs are reasonable"))
    budget_adds_up = models.NullBooleanField(verbose_name=_("Schedule 5: The budget adds up correctly."))
    maximum_amounts_set = models.NullBooleanField(verbose_name=_(
        "Schedule 5: If applicable, maximum amounts for expense categories have been set (i.e., identified with an asterisk (*))."))
    budget_reflects_activity = models.NullBooleanField(verbose_name=_("Schedule 5: The budget reflects the nature of the Activity(ies)."))
    stacking_limits_respected = models.NullBooleanField(
        verbose_name=_("Schedule 5: The federal and stacking limit have been respected, based on confirmed funding."))
    no_funding_redundancy = models.NullBooleanField(verbose_name=_(
        "Schedule 5: The activities and budget items have been cross-checked against DFO Aboriginal program CAs (e.g., SPI-FHRI, AAROM, AFSAR) to ensure no funding redundancy."))
    stacking_identified = models.NullBooleanField(verbose_name=_(
        "Schedule 5: Funding directly related to the RFCPP project coming from DFO Aboriginal programs has been included in the federal and stacking support."))
    confirmation_letters_2_path = models.NullBooleanField(verbose_name=_(
        "Schedule 5: Confirmation letters for all confirmed cash support have been posted to PATH.  Confirmation letters for large amount/potentially inflated in-kind support have also been posted to PATH."))
    financial_information_2_path = models.NullBooleanField(
        verbose_name=_("Schedule 5: Financial information has been updated/entered in PATH as per Data Entry Procedures"))
    conflict_of_interest_assessed = models.NullBooleanField(verbose_name=_(
        "Schedule 5: If a current or former federal public servant is involved in the project, a conflict of interest assessment has been completed (conflict of interest assessment tool found in CA checklist folder in national shared folder) and conflicts, if any, have been addressed, as appropriate."))
    # Schedule 6
    cashflow_adds_up = models.NullBooleanField(
        verbose_name=_("Schedule 6: The cash flow adds up correctly and reflects the timing of Activities."))
    # Schedule 7
    pre_filled_sched7 = models.NullBooleanField(verbose_name=_("Schedule 7: is pre-filled and mirrors Schedule 5"))
    performance_measures_in_path = models.NullBooleanField(verbose_name=_(
        "Schedule 7: Performance measures are updated in the ‘Planned’ column of the performance tab in PATH as per Data Entry Procedures"))
    # General
    team_leader_reviewed = models.NullBooleanField(verbose_name=_("The Team Leader has reviewed and approves the CA"))
    comment_for_nhq = models.TextField(verbose_name=_("Comments for NHQ"), blank=True, null=True)
    review_completion_date = models.DateTimeField(blank=True, null=True)
    # completed_by = models.ForeignKey(User, on_delete=models.DO_NOTHING)

    # meta
    date_last_modified = models.DateTimeField(blank=True, null=True, default=timezone.now, verbose_name=_("date last modified"))
    last_modified_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name=_("last modified by"),
                                         related_name="ca_checklist_last_mods")

    def save(self, *args, **kwargs):
        self.date_last_modified = timezone.now()
        return super().save(*args, **kwargs)

class ExpressionOfInterest(models.Model):
    project = models.OneToOneField(Project, on_delete=models.CASCADE, related_name="eoi")
    date_received = models.DateTimeField(blank=True, null=True, verbose_name=_("date received"))
    description = models.TextField(blank=True, null=True, verbose_name=_("description"))
    coordinator_notified = models.DateTimeField(blank=True, null=True, verbose_name=_("coordinator was notified"))
    project_eligible = models.NullBooleanField(verbose_name=_("is the project eligible?"))
    feedback = models.TextField(blank=True, null=True, verbose_name=_("Feedback to client"))
    feedback_sent = models.DateTimeField(blank=True, null=True, verbose_name=_("feedback sent to client"))

    # meta
    date_last_modified = models.DateTimeField(blank=True, null=True, default=timezone.now, verbose_name=_("date last modified"))
    last_modified_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name=_("last modified by"))

    def save(self, *args, **kwargs):
        self.date_last_modified = timezone.now()
        return super().save(*args, **kwargs)

    @property
    def file(self):
        return File.objects.get(project=self.project, file_type_id=3)

    @property
    def eoi_evaluation_file(self):
        return File.objects.get(project=self.project, file_type_id=7)

class ProjectYear(models.Model):
    project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name="years", verbose_name=_("project language"))
    fiscal_year = models.ForeignKey(shared_models.FiscalYear, on_delete=models.DO_NOTHING, related_name="gc_project_years")
    expenditure_initiation_date = models.DateTimeField(blank=True, null=True, default=datetime.datetime(timezone.now().year, 4, 1))
    paye_number = models.CharField(max_length=50, blank=True, null=True)
    annual_funding = models.FloatField(blank=True, null=True)
    forecasting_notes = models.TextField(blank=True, null=True)
    yearend_reminder_sent = models.DateTimeField(blank=True, null=True)
    lapsing_funds = models.NullBooleanField()
    lapsing_funds_nhq_notified = models.DateTimeField(blank=True, null=True)
    funding_recovery_needed = models.NullBooleanField()
    funding_recovery_email_sent = models.DateTimeField(blank=True, null=True)
    funds_recovered = models.NullBooleanField()
    year_complete = models.DateTimeField(blank=True, null=True)

    # meta
    date_last_modified = models.DateTimeField(blank=True, null=True, default=timezone.now, verbose_name=_("date last modified"))
    last_modified_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name=_("last modified by"))

    def __str__(self):
        return "FY {}".format(self.fiscal_year)

    def save(self, *args, **kwargs):
        self.date_last_modified = timezone.now()
        return super().save(*args, **kwargs)

    class Meta:
        unique_together = ['project', 'fiscal_year']
        ordering = ["project", "fiscal_year"]

    @property
    def payments_issued(self):
        return sum([p.disbursement for p in self.payments.all()])

class ReportType(models.Model):
    name = models.CharField(max_length=255, verbose_name=_("name (English)"))
    nom = models.CharField(max_length=255, blank=True, null=True, verbose_name=_("name (French)"))

    def __str__(self):
        # check to see if a french value is given
        if getattr(self, str(_("name"))):
            return "{}".format(getattr(self, str(_("name"))))
        # if there is no translated term, just pull from the english field
        else:
            return "{}".format(self.name)

    class Meta:
        ordering = [_('name'), ]

class Report(models.Model):
    project_year = models.OneToOneField(ProjectYear, on_delete=models.DO_NOTHING, related_name="reports")
    report_type = models.ForeignKey(ReportType, on_delete=models.DO_NOTHING, related_name="reports")
    date_received = models.DateTimeField(blank=True, null=True, default=timezone.now)
    coordinator_notified = models.DateTimeField(blank=True, null=True)
    coordinator_approved = models.DateTimeField(blank=True, null=True)
    gc_officer_approved = models.DateTimeField(blank=True, null=True)
    manager_approved = models.DateTimeField(blank=True, null=True)
    nhq_notified = models.DateTimeField(blank=True, null=True)

    # meta
    date_last_modified = models.DateTimeField(blank=True, null=True, default=timezone.now, verbose_name=_("date last modified"))
    last_modified_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name=_("last modified by"))

    def save(self, *args, **kwargs):
        self.date_last_modified = timezone.now()
        return super().save(*args, **kwargs)

class ReportChecklist(models.Model):
    report = models.OneToOneField(Report, on_delete=models.DO_NOTHING, related_name="report_checklist")
    recommended_payment_amount = models.FloatField(verbose_name=_("Recommended Payment Amount"))
    # Schedule 7 - General
    sounds_sched7 = models.NullBooleanField(
        verbose_name=_("Schedule 7 matches the one in the signed CA and all sections have been duly filled in."))
    accurate_reporting_period = models.NullBooleanField(verbose_name=_(
        "Reporting period: Where this is the first report submitted by a recipient under the CA, the reporting period commences on the day that RFCPP-funded activities first started taking place."))
    no_missing_period = models.NullBooleanField(verbose_name=_(
        "Reporting period: Where a previous report has been submitted by the recipient under the CA, the reporting period for this report commences the day after the end of the previous reporting period."))

    # Schedule 7 – Section 1
    matching_funds = models.NullBooleanField(verbose_name=_("The “RFCPP funds received year to date” matches the amount in RFCPP records."))
    summed_correctly = models.NullBooleanField(verbose_name=_("Amounts in Table 1.1 are summed correctly."))
    budgeted_amounts_not_exceeded = models.NullBooleanField(
        verbose_name=_("Claimed expenses for expense categories tagged with an asterisk (*) do not exceed the budgeted amount."))
    tab11_no_issues = models.NullBooleanField(verbose_name=_(
        "The amounts reported in Table 1.1 raise no issues and align with the timing of Activities in Schedule 5 and the reporting period."))
    reimbursable_taxes_not_claimed = models.NullBooleanField(
        verbose_name=_("Reimbursable taxes have not been claimed (see application form for percentages reimbursable)."))
    tab12_filled = models.NullBooleanField(verbose_name=_(
        "Table 1.2 has been filled in where budgeted amounts exceed the allowed deviation: a) If the deviation was previously approved by DFO: no action required. b) If the deviation was not previously approved by DFO: review the reason for the deviation and recommend to NHQ (when submitting the report for payment) whether or not the over-expenditure(s) should be reimbursed.  Whether the over-expenditures are reimbursed or not, the recipient must be informed that as per the CA (Sch. 5 s. 6.3) requests for budget reallocations in excess of the set percentage must be submitted to DFO prior to deviating from planned expenditures."))
    confirmation_letters = models.NullBooleanField(verbose_name=_(
        "Confirmation letters for all previously unconfirmed cash support and large in-kind support have been received and posted to PATH (applies to multi-year agreements with supplemental conditions for unconfirmed support)."))
    support_matches = models.NullBooleanField(verbose_name=_(
        "Support received matches what was detailed in the CA. If different, then no effect on federal and stacking limits has been confirmed."))
    actuals_entered = models.NullBooleanField(
        verbose_name=_("All financial information has been entered in the ‘Actual’ section of the financial tab in PATH."))

    # Schedule 7 – Section 2
    deliverables_check_out = models.NullBooleanField(
        verbose_name=_("The status of deliverables matches the claimed expenses and timing of Activities in Schedule 5."))
    invoices_check_out = models.NullBooleanField(verbose_name=_(
        "Where invoices were provided as deliverables, the total(s) of the invoices match what is reported/claimed in Section 1, Table 1.1."))
    sufficient_detail = models.NullBooleanField(verbose_name=_(
        "The quality/level of detail of the deliverables provided is sufficient to recommend payment under s. 34 of the Financial Administration Act (i.e., sufficient information has been provided to justify payment)."))
    tab22_complete = models.NullBooleanField(verbose_name=_(
        "Where Table 2.2 has been filled in: a) Determine whether the explanation may impact the payment amount being requested by the recipient - address with NHQ when submitting the report for payment. b) Determine whether an amendment may be required – address with NHQ when submitting the report for payment (does not apply to final reports). c) Determine whether as a result of cancelled/delayed activities the stacking limit may be exceeded.  If so, the recipient must confirm the actual amounts received from other sources.  If the stacking limit was/will be exceeded, the RFCPP recommended payment must be reduced accordingly to ensure that the staking limit is met."))
    compliant_signage = models.NullBooleanField(verbose_name=_("RFCPP signage follows the RFCPP-FIP Guidelines"))

    # Schedule 7 – Section 3
    tab31_actuals = models.NullBooleanField(verbose_name=_("The “actuals” in Table 3.1 align with the activities and budget table."))
    tab32_complete = models.NullBooleanField(verbose_name=_(
        "All capital acquisitions purchased have been included in Table 3.2 (and align with the costs identified in the budget table)."))
    section3_path_recored = models.NullBooleanField(
        verbose_name=_("All information provided in Section 3 has been recorded in PATH (for final/annual reports only)."))

    # Schedule 7 – Section 4
    section4_signed = models.NullBooleanField(verbose_name=_(
        "Section 4 has been signed by an authorised representative of the Recipient (does not need to be the CA signatory)."))

    # Regional Approval
    sched7_to_path = models.NullBooleanField(
        verbose_name=_("Schedule 7 and all supporting documents (e.g., deliverables) have been posted to PATH."))
    sched6_to_path = models.NullBooleanField(
        verbose_name=_("If a multi-year agreement, Schedule 6 for next year has been received and posted to PATH."))
    site_visit_summary_provided = models.NullBooleanField(
        verbose_name=_("If a site visit was completed for the CA, a summary thereof is provided in the comments section below."))
    team_leader_reviewed = models.NullBooleanField(
        verbose_name=_("The Team Leader has reviewed and approved the recipient report and recommends payment."))

    comments = models.TextField(blank=True, null=True)
    calculations_recommended_payment = models.TextField(blank=True, null=True, verbose_name=_("calculations for recommended payment"))
    review_completion_date = models.DateTimeField(blank=True, null=True)
    completed_by = models.ForeignKey(User, on_delete=models.DO_NOTHING)

    # meta
    date_last_modified = models.DateTimeField(blank=True, null=True, default=timezone.now, verbose_name=_("date last modified"))
    last_modified_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name=_("last modified by"),
                                         related_name="report_checklist_mods")

    def save(self, *args, **kwargs):
        self.date_last_modified = timezone.now()
        return super().save(*args, **kwargs)

class RestorationTypeCategory(models.Model):
    name = models.CharField(max_length=255, verbose_name=_("name (English)"))
    nom = models.CharField(max_length=255, blank=True, null=True, verbose_name=_("name (French)"))

    def __str__(self):
        # check to see if a french value is given
        if getattr(self, str(_("name"))):
            return "{}".format(getattr(self, str(_("name"))))
        # if there is no translated term, just pull from the english field
        else:
            return "{}".format(self.name)

    class Meta:
        ordering = [_('name'), ]

class RestorationType(models.Model):
    restoration_type_category = models.ForeignKey(RestorationTypeCategory, on_delete=models.DO_NOTHING, related_name="types")
    name = models.TextField(verbose_name=_("name (English)"))
    nom = models.TextField(blank=True, null=True, verbose_name=_("name (French)"))

    def __str__(self):
        # check to see if a french value is given
        if getattr(self, str(_("name"))):
            return "{}".format(getattr(self, str(_("name"))))
        # if there is no translated term, just pull from the english field
        else:
            return "{}".format(self.name)

    class Meta:
        ordering = [_('name'), ]

class SiteType(models.Model):
    name = models.TextField(verbose_name=_("name (English)"))
    nom = models.TextField(blank=True, null=True, verbose_name=_("name (French)"))

    def __str__(self):
        # check to see if a french value is given
        if getattr(self, str(_("name"))):
            return "{}".format(getattr(self, str(_("name"))))
        # if there is no translated term, just pull from the english field
        else:
            return "{}".format(self.name)

    class Meta:
        ordering = [_('name'), ]

class Site(models.Model):
    project = models.ForeignKey(Project, on_delete=models.DO_NOTHING, related_name="sites")
    name = models.CharField(max_length=255, verbose_name=_("site name"))
    site_type = models.ForeignKey(SiteType, on_delete=models.DO_NOTHING, related_name="sites", verbose_name=_("site type"))
    lat = models.FloatField(max_length=255, verbose_name=_("latitude (DD.dddddd)"), blank=True, null=True)
    long = models.FloatField(max_length=255, verbose_name=_("longitude (DD.dddddd)"), blank=True, null=True, validators=[MaxValueValidator(0),])
    restoration_type = models.ForeignKey(RestorationType, on_delete=models.DO_NOTHING, related_name="sites", verbose_name=_("restoration type (optional)"), blank=True, null=True)
    width = models.CharField(max_length=255, verbose_name=_("width (optional)"), blank=True, null=True)
    depth = models.CharField(max_length=255, verbose_name=_("depth (optional)"), blank=True, null=True)
    substrate = models.CharField(max_length=255, verbose_name=_("substrate (optional)"), blank=True, null=True)
    comments = models.TextField(verbose_name=_("comments"), blank=True, null=True)

    def __str__(self):
        # check to see if a french value is given
        if getattr(self, str(_("name"))):
            return "{}".format(getattr(self, str(_("name"))))
        # if there is no translated term, just pull from the english field
        else:
            return "{}".format(self.name)

    class Meta:
        ordering = [_('name'), ]

class SiteVisit(models.Model):
    project_year = models.OneToOneField(ProjectYear, on_delete=models.DO_NOTHING, related_name="site_visits")
    date_of_visit = models.DateTimeField(blank=True, null=True, default=timezone.now)
    personnel_1 = models.ForeignKey(User, on_delete=models.DO_NOTHING, related_name="site_visits_per1")
    personnel_2 = models.ForeignKey(User, on_delete=models.DO_NOTHING, related_name="site_visits_per2")

    # QUARTERLY DOCUMENTED ROUTINE REVIEW (REQUIRED)
    c1 = models.NullBooleanField(verbose_name=_(
        "C.1 Was the work completed as proposed in the CA (activities/tasks, timing and budget)? If not, is an amendment or note-to-file required? Provide details."))
    c1_comment = models.CharField(max_length=500, blank=True, null=True, verbose_name=_("C.1 comments"))

    c2 = models.NullBooleanField(verbose_name=_(
        "C.2 Are there any challenges affecting delivery of the project (e.g., contractors/personnel issues, required permits, site conditions)? If so, provide details."))
    c2_comment = models.CharField(max_length=500, blank=True, null=True, verbose_name=_("C.2 comments"))

    c3 = models.NullBooleanField(verbose_name=_("C.3 Was the sign installed?  If not, provide details."))
    c3_comment = models.CharField(max_length=500, blank=True, null=True, verbose_name=_("C.3 comments"))

    c4 = models.NullBooleanField(verbose_name=_("C.4 Were photos taken? If so, ensure that photos are posted to PATH."))
    c4_comment = models.CharField(max_length=500, blank=True, null=True, verbose_name=_("C.4 comments"))

    c5 = models.NullBooleanField(verbose_name=_(
        "C.5 Is a follow up site visit (or other follow-up) required? If yes, describe reasons for requiring follow-up, the type of follow-up, and when it is to occur."))
    c5_comment = models.CharField(max_length=500, blank=True, null=True, verbose_name=_("C.5 comments"))

    # PROGRAM IMPROVEMENT (REQUIRED)
    c6 = models.NullBooleanField(verbose_name=_(
        "C.6 Does the group have any feedback on the Program (positive feedback or suggested improvements)?  Provide details."))
    c6_comment = models.CharField(max_length=500, blank=True, null=True, verbose_name=_("C.6 comments"))

    # PROJECT EVALUATION (OPTIONAL)
    c7 = models.NullBooleanField(verbose_name=_("C.7 Were the structure(s)/works designed/installed properly?  If not, provide details."))
    c7_comment = models.CharField(max_length=500, blank=True, null=True, verbose_name=_("C.7 comments"))

    c8 = models.NullBooleanField(
        verbose_name=_("C.8 Did the work address the key issues at the site / is it functioning as intended? If not, provide details."))
    c8_comment = models.CharField(max_length=500, blank=True, null=True, verbose_name=_("C.8 comments"))

    c9 = models.NullBooleanField(verbose_name=_("C.9 Are recreational fish using the site/have access to the site?"))
    c9_comment = models.CharField(max_length=500, blank=True, null=True, verbose_name=_("C.9 comments"))

    c10 = models.NullBooleanField(verbose_name=_("C.10 Are there concerns with any aspect of the work? If yes, provide details."))
    c10_comment = models.CharField(max_length=500, blank=True, null=True, verbose_name=_("C.10 comments"))

    c11 = models.NullBooleanField(verbose_name=_("C.11 Were any suggestions made for future projects? If yes, provide details."))
    c11_comment = models.CharField(max_length=500, blank=True, null=True, verbose_name=_("C.11 comments"))

    # SUMMARY
    summary = models.TextField(blank=True, null=True, verbose_name=_("Summary of Findings and/or Follow-up Actions (if applicable)"))

    # meta
    date_last_modified = models.DateTimeField(blank=True, null=True, default=timezone.now, verbose_name=_("date last modified"))
    last_modified_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name=_("last modified by"))

    def save(self, *args, **kwargs):
        self.date_last_modified = timezone.now()
        return super().save(*args, **kwargs)

def file_directory_path(instance, filename):
    # file will be uploaded to MEDIA_ROOT/entry_<id>/<filename>
    return 'spot/{0}/{1}'.format(instance.project.id, filename)

class Photo(models.Model):
    caption = models.CharField(max_length=255)
    site_visit = models.ForeignKey(SiteVisit, related_name="photos", on_delete=models.CASCADE)
    file = models.FileField(upload_to=file_directory_path)
    # meta
    date_created = models.DateTimeField(default=timezone.now)
    uploaded_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name=_("uploaded"))

    class Meta:
        ordering = ['-date_created']

    def __str__(self):
        return self.caption

class FileType(models.Model):
    name = models.CharField(max_length=255, verbose_name=_("name (English)"))
    nom = models.CharField(max_length=255, blank=True, null=True, verbose_name=_("name (French)"))

    def __str__(self):
        # check to see if a french value is given
        if getattr(self, str(_("name"))):
            return "{}".format(getattr(self, str(_("name"))))
        # if there is no translated term, just pull from the english field
        else:
            return "{}".format(self.name)

    class Meta:
        ordering = [_('name'), ]

class File(models.Model):
    project = models.ForeignKey(Project, related_name="files", on_delete=models.CASCADE)
    caption = models.CharField(max_length=255, blank=True, null=True, verbose_name=_("file caption (optional)"))
    file_type = models.ForeignKey(FileType, related_name="files", on_delete=models.DO_NOTHING)
    file = models.FileField(upload_to=file_directory_path)
    # meta
    date_modified = models.DateTimeField(default=timezone.now)
    uploaded_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name=_("uploaded by"))

    class Meta:
        ordering = ['file_type']

    def __str__(self):
        my_str = str(self.file_type)
        if self.caption:
            my_str = "{} - {}".format(my_str, self.caption)
        return my_str

    def save(self, *args, **kwargs):
        self.date_modified = timezone.now()
        return super().save(*args, **kwargs)

class Payment(models.Model):
    project_year = models.ForeignKey(ProjectYear, related_name="payments", on_delete=models.CASCADE)
    claim_number = models.IntegerField()
    advance_amount = models.FloatField(default=0)
    reimbursement_amount = models.FloatField(default=0)
    from_period = models.DateTimeField(blank=True, null=True)
    to_period = models.DateTimeField(blank=True, null=True)
    final_payment = models.BooleanField(default=False, verbose_name=_("Is this a final payment (project-year)?"))
    materials_submitted = models.NullBooleanField(verbose_name=_("were all necessary materials submitted?"))
    nhq_notified = models.DateTimeField(blank=True, null=True, verbose_name=_("NHQ notified"))
    payment_confirmed = models.NullBooleanField(verbose_name=_("has the payment been confirmed?"))
    notes = models.TextField(blank=True, null=True)

    # meta
    date_last_modified = models.DateTimeField(blank=True, null=True, default=timezone.now, verbose_name=_("date last modified"))
    last_modified_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name=_("last modified by"))

    def save(self, *args, **kwargs):
        self.date_last_modified = timezone.now()
        return super().save(*args, **kwargs)

    class Meta:
        unique_together = ['project_year', 'claim_number']

    @property
    def disbursement(self):
        return self.advance_amount + self.reimbursement_amount

def determine_project_status(project):
    ignore_statuses = [2, 4, 5, 7, 11, 12, 13]
    # first check to see if this function should be escaped
    if project.status_id in ignore_statuses:
        return project.status_id

    # otherwise we assess status
    else:
        # start backwards
        if project.date_completed:
            # means project is over
            return 13
        elif project.final_ca_nhq_signed:
            # means there is a signed agreement inplace. Status should be changed to 'active'
            return 10
        elif nz(project.recommended_overprogramming, 0) > 0:
            # means project is on OP
            return 8
        elif project.total_recommended_funding > 0:
            # means funding has been recommended
            return 9
        elif project.submission_accepted == False:
            # means submission has not been accepted
            return 5
        elif project.submission_accepted == True:
            # means submission was successful
            return 6
        elif ExpressionOfInterest.objects.filter(project=project).count() > 0:
            # means an eoi was submitted
            if project.eoi.project_eligible == False:
                # means project was deemed eligible
                return 2
            elif project.eoi.project_eligible == True:
                # means project was deemed ineligible
                return 3
            else:
                return 1
        else:
            print("returning default status")
            return project.status_id

def determine_project_length(project, status_id):
    # depending on the status, we should set the project length
    my_length = 0

    if status_id == 8:
        # an OP project can only be for 1 year
        my_length = 1
    elif status_id == 9:
        # recommended project will be based on the number of years recommended
        if nz(project.recommended_funding_y1, 0) > 0:
            my_length += 1
        if nz(project.recommended_funding_y2, 0) > 0:
            my_length += 1
        if nz(project.recommended_funding_y3, 0) > 0:
            my_length += 1
        if nz(project.recommended_funding_y4, 0) > 0:
            my_length += 1
        if nz(project.recommended_funding_y5, 0) > 0:
            my_length += 1
    elif status_id == 10:
        # active project will be based on the number of project-years
        my_length = project.years.count()

    else:
        my_length = None

    return my_length

#
# @receiver(models.signals.post_delete, sender=Project)
# def auto_delete_draft_ca_on_delete(sender, instance, **kwargs):
#     """
#     Deletes file from filesystem
#     when corresponding `MediaFile` object is deleted.
#     """
#     # for draft ca
#     if instance.draft_ca:
#         if os.path.isfile(instance.draft_ca.path):
#             os.remove(instance.draft_ca.path)
#
#
# @receiver(models.signals.pre_save, sender=Project)
# def auto_delete_draft_ca_on_change(sender, instance, **kwargs):
#     """
#     Deletes old file from filesystem
#     when corresponding `MediaFile` object is updated
#     with new file.
#     """
#     if not instance.pk:
#         return False
#
#     # for draft ca
#     try:
#         old_file = Project.objects.get(pk=instance.pk).draft_ca
#     except Project.DoesNotExist:
#         return False
#
#     if old_file:
#         new_file = instance.draft_ca
#         if not old_file == new_file:
#             if os.path.isfile(old_file.path):
#                 os.remove(old_file.path)

@receiver(models.signals.post_delete, sender=Photo)
def auto_delete_photo_on_delete(sender, instance, **kwargs):
    """
    Deletes file from filesystem
    when corresponding `MediaFile` object is deleted.
    """
    if instance.file:
        if os.path.isfile(instance.file.path):
            os.remove(instance.file.path)

@receiver(models.signals.pre_save, sender=Photo)
def auto_delete_photo_on_change(sender, instance, **kwargs):
    """
    Deletes old file from filesystem
    when corresponding `MediaFile` object is updated
    with new file.
    """
    if not instance.pk:
        return False

    try:
        old_file = Photo.objects.get(pk=instance.pk).file
    except Photo.DoesNotExist:
        return False

    if old_file:
        new_file = instance.file
        if not old_file == new_file:
            if os.path.isfile(old_file.path):
                os.remove(old_file.path)

@receiver(models.signals.post_delete, sender=File)
def auto_delete_file_on_delete(sender, instance, **kwargs):
    """
    Deletes file from filesystem
    when corresponding `MediaFile` object is deleted.
    """
    if instance.file:
        if os.path.isfile(instance.file.path):
            os.remove(instance.file.path)

@receiver(models.signals.pre_save, sender=File)
def auto_delete_file_on_change(sender, instance, **kwargs):
    """
    Deletes old file from filesystem
    when corresponding `MediaFile` object is updated
    with new file.
    """
    if not instance.pk:
        return False

    try:
        old_file = File.objects.get(pk=instance.pk).file
    except File.DoesNotExist:
        return False

    if old_file:
        new_file = instance.file
        if not old_file == new_file:
            if os.path.isfile(old_file.path):
                os.remove(old_file.path)


"""
    PREDICT COMPARE.py
        by Tim Müller

    This script tries to predict the optimal running time for a given
    application using different analytical models. For the input, it uses those
    as found in a benchmarking CSV, and shows us the difference between the
    predicted and actual runtimes.
"""

import argparse
import pandas as pd
import numpy as np
import os
import sys
from collections import defaultdict

DEFAULT_CSV = "benchmark_results.csv"
DEFAULT_MODEL_FOLDER = "analytical_models/"
DEFAULT_OUTPUT_FILE = "rankings.csv"

# Fill in the machine performance data please (as (peak_performance, peak_bandwidth, peak_performance_avx, peak_bandwidth_avx)) The bandwidth is over a single core.
# NOTE: hall GFLOP/s from https://www.intel.com/content/dam/support/us/en/documents/processors/APP-for-Intel-Core-Processors.pdf
# NOTE: all GB/s obtained with LIKWID (copy or copy-avx, 1GB load).
# NOTE: First two are non-simd, second two are yes-simd
# NOTE: GPU Stats from https://www.techpowerup.com/gpu-specs/geforce-rtx-2080.c3224 and https://www.techpowerup.com/gpu-specs/geforce-gtx-titan-x.c2632; beta_C_G is from https://www.gamersnexus.net/guides/2488-pci-e-3-x8-vs-x16-performance-impact-on-gpus
MACHINES = {
    "home_desktop": {
        1: (7.2, 14.93606, 28.8, 14.33228),
        2: (14.4, 15.86464, 57.6, 15.65240),
        4: (28.8, 16.50343, 115.2, 17.38215),
        8: (57.6, 16.94652, 230.4, 17.19413),
        16: (115.2, 17.09865, 460.8, 17.09826),
        32: (115.2, 17.01528, 460.8, 17.18359),
        "GPU": (10070.0, 448, 15.760)
    },
    "DAS5_1numa": {
        1: (2.4, 11.53074, 9.6, 11.42862),
        2: (4.8, 12.49312, 19.2, 12.27604),
        4: (9.6, 22.43777, 38.4, 20.62895),
        8: (19.2, 30.47322, 76.8, 27.52148),
        16: (38.4, 31.12496, 153.6, 28.11800),
        32: (76.8, 31.10337, 307.2, 28.10550)
    },
    "DAS5": {
        1: (2.4, 11.53074, 9.6, 11.42862),
        2: (4.8, 22.61996, 19.2, 21.99305),
        4: (9.6, 24.99948, 38.4, 24.37255),
        8: (19.2, 45.96919, 76.8, 41.58752),
        16: (38.4, 60.74498, 153.6, 55.02765),
        32: (76.8, 62.18000, 307.2, 56.00466),
        "GPU": (6691.0, 336.6, 15.760)
    },
    "macbook": {
        1: (5.8, 11.16392, 11.6, 11.26597),
        2: (11.6, 10.22710, 23.2, 10.38897),
        4: (23.2, 11.60071, 46.4, 11.72698),
        8: (23.2, 11.54814, 46.4, 11.68686),
        16: (23.2, 11.55648, 46.4, 11.67511),
        32: (23.2, 11.55118, 46.4, 11.57948)
    },
    "lisa": {
        1: (2.0, 13.21974, 16.0, 13.28313),
        2: (4.0, 25.49654, 32.0, 25.20818),
        4: (8.0, 47.30837, 64.0, 46.33363),
        8: (16.0, 47.05812, 128.0, 45.97598),
        16: (32.0, 60.49140, 256.0, 60.60499),
        32: (32.0, 65.63927, 256.0, 66.84047)
    }
}

def main(models_path, csv_files, output_path, filter_threads, show_all, show_none):
    print("\n### PREDICTION TOOL for ANALYTICAL MODELS ###\n")

    print(f"Tool configuration:")
    print(f" - Models folder       : {models_path}")
    if len(filter_threads) > 0: print(f" - Threads to display  : {', '.join(filter_threads)}")
    print(f" - Benchmark datafiles :")
    for csv in csv_files:
        print(f"    - '{csv}'")
    print("")

    print("Loading benchmark results... ", end="")
    sys.stdout.flush()
    data = pd.DataFrame()
    for csv in csv_files:
        csv_data = pd.read_csv(csv)
        data = pd.concat([data, csv_data], ignore_index=True)
    # Check if we got any
    if len(data) == 0:
        print(f"\n\nERROR: No benchmarks found in any of the given files.", file=sys.stderr)
        return -1
    print(f"Done (loaded {len(data)} benchmark(s))")

    print("Loading model implementations... ", end="")
    sys.stdout.flush()
    sys.path.append(models_path)
    models = {}
    for variation in data["variation"].unique():
        try:
            models[variation] = __import__(variation, fromlist=[variation])
        except ModuleNotFoundError:
            print(f"\n\nERROR: Could not load file '{variation}.py' from '{models_path}'.", file=sys.stderr)
            return -1
    print(f"Done (loaded {len(models)} models)")

    print("Reading benchmarks... ", end="")
    sys.stdout.flush()
    parameters = defaultdict(lambda: defaultdict(lambda: {"n": 0, "data": None}))
    for i, row in data.iterrows():
        # Get the parameter set as tuple
        hw_imp_pair = tuple(row.iloc[0:2]) + tuple([row.iloc[3]])
        # Stop if not filtered out
        if len(filter_threads) > 0 and str(hw_imp_pair[2]) not in filter_threads: continue
        parameter_set = tuple(row.iloc[4:10])
        if parameters[parameter_set][hw_imp_pair]["n"] == 0:
            parameters[parameter_set][hw_imp_pair]["data"] = np.array(row.iloc[10:])
        else:
            parameters[parameter_set][hw_imp_pair]["data"] += np.array(row.iloc[10:])
        parameters[parameter_set][hw_imp_pair]["n"] += 1
    # Once done, average all things
    parameters = {
        params: {
            hw_imp_pair: tuple(parameters[params][hw_imp_pair]["data"] / parameters[params][hw_imp_pair]["n"]) for hw_imp_pair in parameters[params]
        } for params in parameters
    }
    print("Done\n")

    if len(parameters) == 0:
        print("Nothing to do.\n")
        return 0

    print("Opening output file... ", end="")
    try:
        output = open(output_path, "w")
    except OSError as e:
        print(f"\nERROR: Could not open file \"{output_path}\": {e.strerror}\n")
        return -1
    print("Done")
    print("Writing CSV headers... ", end="")
    output.write("ranking_id,ranking_position,n_hidden_layers,nodes_per_layer,n_epochs,n_samples,sample_size,n_classes,predicted_machine,predicted_variation,predicted_n_threads,predicted_runtime,benchmarked_machine,benchmarked_variation,benchmarked_n_threads,benchmarked_runtime\n")
    print("Done\n")

    # Time to predict
    print("Predicting and comparing...")
    total = 0
    correct = 0
    hw_total = defaultdict(int)
    hw_incorrect = defaultdict(int)
    var_total = defaultdict(int)
    var_incorrect = defaultdict(int)
    thread_total = defaultdict(int)
    thread_incorrect = defaultdict(int)
    time_offset = defaultdict(lambda: defaultdict(list))
    for params in parameters:
        config_set = parameters[params]
        predicted_ranking = []
        benchmark_ranking = []
        for machine_id, variation, n_threads in config_set:
            # Predict the runtime for this ranking
            predicted_ranking.append([machine_id, variation, n_threads] + [runtime for runtime in models[variation].predict(params, MACHINES[machine_id], n_threads)])
            # Also add the runtimes for the benchmarking
            benchmark_ranking.append([machine_id, variation, n_threads] + [runtime for runtime in config_set[(machine_id, variation, n_threads)]])

        # Sort both rankings to actually rank them
        predicted_ranking = sorted(predicted_ranking, key=lambda elem: elem[3])
        benchmark_ranking = sorted(benchmark_ranking, key=lambda elem: elem[3])

        # Compare if the machines are the same
        matches = True
        for i in range(len(config_set)):
            machine_id = predicted_ranking[i][0]
            variation = predicted_ranking[i][1]
            n_threads = predicted_ranking[i][2]

            # Update the total
            hw_total[machine_id] += 1
            var_total[variation] += 1
            thread_total[n_threads] += 1

            # Compute and store the time offset
            offset = benchmark_ranking[i][3] / predicted_ranking[i][3]
            time_offset[(machine_id, n_threads)][variation].append(offset)

            if machine_id != benchmark_ranking[i][0] or variation != benchmark_ranking[i][1]:
                matches = False
                # Add an incorrect mark to both the hardware and the incorrect
                hw_incorrect[machine_id] += 1
                var_incorrect[variation] += 1
                thread_incorrect[n_threads] += 1

            # Print the ranking
            output.write(f"{total},{i},{','.join([str(p) for p in params])},{machine_id},{variation},{n_threads},{predicted_ranking[i][3]},{benchmark_ranking[i][0]},{benchmark_ranking[i][1]},{benchmark_ranking[i][2]},{benchmark_ranking[i][3]}\n")

        # If they aren't, let the user know
        if not show_none and (show_all or not matches):
            # Print that they differ
            line_size = 60
            print(f"\nResults for parameters {params} (id {total}) differ:")
            print("  Predicted:" + " " * (line_size - 6) + "Benchmarked:")
            for i in range(len(config_set)):
                n_threads = predicted_ranking[i][2]
                text = f"   {i + 1}) {predicted_ranking[i][0].upper()} ({n_threads} thread{'' if n_threads == 1 else 's'}) with {predicted_ranking[i][1].upper()} ({predicted_ranking[i][3]:.4f}s)"
                text += " " * (line_size - len(text)) + " VS "
                n_threads = benchmark_ranking[i][2]
                text += f"   {i + 1}) {benchmark_ranking[i][0].upper()} ({n_threads} thread{'' if n_threads == 1 else 's'}) with {benchmark_ranking[i][1].upper()} ({benchmark_ranking[i][3]:.4f}s)"
                print(text)
            print("")

        # Update the accuracy score
        total += 1
        correct += 1 if matches else 0

    # Convert time_offset in a normal dictionary
    time_offset = {m: {v: time_offset[m][v].copy() for v in time_offset[m]} for m in time_offset}

    print("\n***STATS***\n")
    print("Ranking accuracy:")
    print(f" - Overall accuracy: {(correct / total * 100):.2f}%")
    print(" - Accuracy per machine:")
    for m in hw_total:
        print(f"    - {m} : {(hw_total[m] - hw_incorrect[m]) / hw_total[m] * 100:.2f}%")
    print(" - Accuracy per variation:")
    for v in var_total:
        print(f"    - {v} : {(var_total[v] - var_incorrect[v]) / var_total[v] * 100:.2f}%")
    print(" - Accuracy per amount of threads:")
    for t in thread_total:
        print(f"    - {t} : {(thread_total[t] - thread_incorrect[t]) / thread_total[t] * 100:.2f}%")

    print("\nRatio of prediction time to benchmark time per machine (number of threads), per variation:")
    for m, t in time_offset:
        print(f" - {m} ({t} threads):")
        for v in time_offset[(m, t)]:
            offsets = time_offset[(m, t)][v]
            print(f"    - {v}:")

            # Compute the mean first
            mean = sum(offsets) / len(offsets)
            print(f"       - mean     = {mean:.2f}x")

            # Then, the variance
            var = sum([(mean - offset) ** 2 for offset in offsets]) / len(offsets)
            print(f"       - variance = {var:.2f}")

    print("\nDone.\n")

    output.close()
    return 0

if __name__ == "__main__":
    parser = argparse.ArgumentParser()

    parser.add_argument("-o", "--output", default=DEFAULT_OUTPUT_FILE, required=False, help=f"Path the output file to which the rankings will be written. (Default: {DEFAULT_OUTPUT_FILE})")
    parser.add_argument("-c", "--csvs", nargs='+', required=True, help=f"Files to load the benchmarks from. Can be more than one, which will be pasted internally after one another.")
    parser.add_argument("-M", "--models", default=DEFAULT_MODEL_FOLDER, required=False, help=f"Path to the folder containing the model implementations. (Default: {DEFAULT_MODEL_FOLDER})")
    parser.add_argument("-a", "--all", action="store_true", help="If given, displays all rankings instead of just the incorrect ones.")
    parser.add_argument("-s", "--silent", action="store_true", help="If given, displays no rankings at all (overrides --all).")
    parser.add_argument("-t", "--threads", default=[], nargs='+', help="The numbers of threads to keep. All other n_threads will be filtered out. If omitted, displays all threads")

    args = parser.parse_args()

    # Check the validity of the CSV files
    csvs = []
    while len(args.csvs) > 0:
        csv = args.csvs[0]
        args.csvs = args.csvs[1:]

        if not os.path.exists(csv):
            print(f"ERROR: File '{csv}' does not exist.", file=sys.stderr)
            exit(-1)
        if os.path.isdir(csv):
            # Append all this folder's children to the list
            csvs += [os.path.join(csv, f) for f in os.listdir(csv)]
            continue
        elif not os.path.isfile(csv):
            print(f"ERROR: File '{csv}' is not a file.", file=sys.stderr)
            exit(-1)

        # Append the file
        csvs.append(csv)

    # Check if the models folder exists
    if not os.path.exists(args.models):
        print(f"ERROR: Folder '{args.models}' does not exist.", file=sys.stderr)
        exit(-1)
    if not os.path.isdir(args.models):
        print(f"ERROR: Folder '{args.models}' is not a folder.", file=sys.stderr)
        exit(-1)

    # So far so good, let's run main
    exit(main(args.models, csvs, args.output, args.threads, args.all, args.silent))


import sys
from collections import deque
read = lambda: sys.stdin.readline().strip()

# set prime table
prime = [1] * 10001
for i in range(2, 5000):
    if prime[i]:
        for j in range(i + i, 10001, i):
            prime[j] = 0

def bfs():
    queue = deque([(first, 0)])
    while queue:
        now, step = queue.popleft()
        if now == last:
            return step

        NOW = str(now)
        step += 1
        for i in range(4):
            for j in map(str, range(10)):
                if i == 0 and j == '0':
                    continue
                num = int(NOW[:i] + j + NOW[i + 1:])
                if prime[num] and not visited[num]:
                    visited[num] = 1
                    queue.append((num, step))

T = int(read())
for _ in range(T):
    first, last = map(int, read().split())
    visited = [0] * 10001
    print(bfs())


from django.conf import settings
from django.core.validators import MinValueValidator, RegexValidator
from django.db import models

from users.models import User

class NameModel(models.Model):
    name = models.CharField('название', max_length=200, unique=True)

    class Meta:
        abstract = True

    def __str__(self):
        return self.name

class Tag(NameModel):
    color = models.CharField('цвет в HEX', max_length=7, unique=True)
    slug = models.CharField(
        'уникальный слаг',
        max_length=200,
        unique=True,
        validators=[
            RegexValidator(
                regex=r'^[-a-zA-Z0-9_]+$',
                message='Недопустимый формат слага',
            ),
        ],
    )

    class Meta:
        verbose_name = 'тег'
        verbose_name_plural = 'теги'
        ordering = ('name',)

class Ingredient(NameModel):
    measurement_unit = models.CharField('единица измерения', max_length=200)

    class Meta:
        verbose_name = 'ингредиент'
        verbose_name_plural = 'ингредиенты'
        ordering = ('name',)

class Recipe(NameModel):
    ingredients = models.ManyToManyField(
        Ingredient,
        through='RecipeIngredients',
        verbose_name='список ингредиентов',
    )
    tags = models.ManyToManyField(Tag, verbose_name='список id тегов')
    image = models.ImageField('картинка', upload_to='recipes/media/')
    author = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        verbose_name='автор',
    )
    text = models.TextField('описание')
    cooking_time = models.PositiveSmallIntegerField(
        'время приготовления (в минутах)',
        validators=(MinValueValidator(settings.MIN_FIELD_RESTRICTION),),
    )

    class Meta:
        verbose_name = 'рецепт'
        verbose_name_plural = 'рецепты'
        default_related_name = 'recipes'
        ordering = ('-id',)

class RecipeIngredients(models.Model):
    recipe = models.ForeignKey(
        Recipe,
        on_delete=models.CASCADE,
        verbose_name='рецепт',
    )
    ingredient = models.ForeignKey(
        Ingredient,
        on_delete=models.CASCADE,
        verbose_name='ингредиент',
    )
    amount = models.PositiveIntegerField(
        'количество',
        validators=(MinValueValidator(settings.MIN_FIELD_RESTRICTION),),
    )

    class Meta:
        verbose_name = 'through-модель ингредиентов в рецепте'
        verbose_name_plural = 'through-модели ингредиентов в рецепте'
        constraints = [
            models.UniqueConstraint(
                fields=('recipe', 'ingredient'),
                name='unique_ingredients',
            ),
        ]
        default_related_name = 'recipe_ingredients'
        ordering = ('-id',)

    def __str__(self):
        return f'В рецепте {self.recipe} содержится {self.ingredient}'

class UserRecipeModel(models.Model):
    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        verbose_name='пользователь',
    )
    recipe = models.ForeignKey(
        Recipe,
        on_delete=models.CASCADE,
        verbose_name='рецепт',
    )

    class Meta:
        abstract = True

class Favorite(UserRecipeModel):
    class Meta:
        verbose_name = 'избранное'
        verbose_name_plural = 'избранное'
        default_related_name = 'favorites'

        constraints = (
            models.UniqueConstraint(
                fields=('user', 'recipe'),
                name='unique_favorite',
            ),
        )

    ordering = ('-id',)

    def __str__(self):
        return f'{self.user} добавил рецепт {self.recipe} в избранное'

class ShoppingCart(UserRecipeModel):
    class Meta:
        verbose_name = 'покупка'
        verbose_name_plural = 'покупки'
        default_related_name = 'shopping_cart'

        constraints = (
            models.UniqueConstraint(
                fields=('user', 'recipe'),
                name='unique_shopping_list_recipe',
            ),
        )
        ordering = ('-id',)

    def __str__(self):
        return f'Рецепт {self.recipe} в списке покупок у {self.user}'


"""Seed file to make sample data for pets db."""

from models import Image, db
from app import app
import datetime

now = datetime.datetime.now()

# Create all tables
db.drop_all()
db.create_all()

image1 = Image(
    date_time_created=now.strftime("%m/%d/%Y, %H:%M:%S"),
    date_time_uploaded=now,
    gps_latitude="40.76",
    gps_longitude="40.76",
    make="EASTMAN KODAK COMPANY",
    model="KODAK CX7530 ZOOM DIGITAL CAMERA",
    path="img.jpeg",
    caption="I am a test caption")

image2 = Image(
    date_time_created=now.strftime("%m/%d/%Y, %H:%M:%S"),
    date_time_uploaded=now,
    gps_latitude="40.76",
    gps_longitude="40.76",
    make="FUJIFILM",
    model="FinePix6900ZOOM",
    path="img2.jpeg",
    caption="I am not a test caption")

db.session.add_all([image1, image2])
db.session.commit()


import asyncio

from absl.testing import absltest

from tensorflow_federated.python.common_libs import async_utils

async def _sleep_then_append(entries, value):
  await asyncio.sleep(0.01)
  entries.append(value)

class OrderedTasksTest(absltest.TestCase):

  def test_runs_awaitable(self):
    nums = []

    async def run():
      async with async_utils.ordered_tasks() as tasks:
        tasks.add(_sleep_then_append(nums, 0))

    asyncio.run(run())
    self.assertEqual(nums, [0])

  def test_runs_awaitable_in_separate_task_while_in_context(self):

    async def run():
      event = asyncio.Event()

      async def awaitable():
        await asyncio.sleep(0.01)
        event.set()

      async with async_utils.ordered_tasks() as tasks:
        tasks.add(awaitable())
        await asyncio.wait_for(event.wait(), timeout=10)

    asyncio.run(run())

  def test_runs_despite_exception_and_logs(self):
    nums = []

    async def _sleep_then_append_then_throw(entries, value):
      await asyncio.sleep(0.01)
      entries.append(value)
      raise ValueError('async throwing')

    def _append_then_throw():
      nums.append(1)
      raise ValueError('sync throwing')

    async def run():
      async with async_utils.ordered_tasks() as tasks:
        tasks.add(_sleep_then_append_then_throw(nums, 0))
        tasks.add_callable(_append_then_throw)
        tasks.add(_sleep_then_append_then_throw(nums, 2))

    with self.assertLogs() as logs:
      asyncio.run(run())
    self.assertEqual(nums, [0, 1, 2])
    self.assertLen(logs.records, 3)

  def test_runs_awaitables(self):
    nums = []

    async def run():
      async with async_utils.ordered_tasks() as tasks:
        tasks.add_all(*(_sleep_then_append(nums, n) for n in range(3)))

    asyncio.run(run())
    self.assertSameElements(nums, list(range(3)))

  def test_runs_sync_after_awaitable(self):
    nums = []

    async def run():
      async with async_utils.ordered_tasks() as tasks:
        tasks.add(_sleep_then_append(nums, 0))
        tasks.add_callable(lambda: nums.append(1))

    asyncio.run(run())
    self.assertEqual(nums, [0, 1])

class SharedAwaitableTest(absltest.TestCase):

  async def async_five(self):
    return 5

  def test_await_once_returns_result(self):

    async def x():
      self.assertEqual(await async_utils.SharedAwaitable(self.async_five()), 5)

    asyncio.run(x())

  def test_await_several_times_returns_result(self):

    async def x():
      async_result = async_utils.SharedAwaitable(self.async_five())
      self.assertEqual(await async_result, 5)
      self.assertEqual(await async_result, 5)
      self.assertEqual(await async_result, 5)
      self.assertEqual(await async_result, 5)

    asyncio.run(x())

  async def async_raise_value_error(self):
    raise ValueError('error')

  def test_reraises_exception_on_await(self):

    async def x():
      async_raiser = async_utils.SharedAwaitable(self.async_raise_value_error())
      with self.assertRaises(ValueError):
        await async_raiser

    asyncio.run(x())

if __name__ == '__main__':
  absltest.main()


import numpy as np
from PIL import Image

train_path= 'data/train_set/'
test_path='data/test_set/'
data= np.load('cloud.npy')
total=len(data)
test=int(total*0.01)
train=total-test
print(train)
for i in range(total):
    x= np.reshape(data[i],(28,28))
    img=Image.fromarray(x)
    img=img.convert('L')
    if(i<train):
        img.save(train_path+"cloud/cloud"+str(i)+".png")
    else:
        img.save(test_path+"cloud/cloud"+str(i-train)+".png")
print('done')


"""Evaluates the model"""

import argparse
import os

import numpy as np
import torch
import utils
import pandas as pd
import math
from wordcloud import WordCloud
import re

parser = argparse.ArgumentParser()
parser.add_argument('--config_dir', default='/home/ugrads/j/justinlovelace/MIMIC/ICU_Readmit/resources', help="Directory containing params.json")

def create_global_wordcloud(model_dir, save_dir, high_risk=True, ratio=0.05):
    img_directory = os.path.join(save_dir, 'visualizations', 'global')
    if not os.path.exists(img_directory):
        os.makedirs(img_directory)
    df_attn_weights = pd.read_csv(os.path.join(model_dir, 'df_attn.csv'))
    datasetPath = os.path.join(save_dir, 'df_master.csv')
    # df_attn_weights.to_csv(datasetPath, index=False)
    target_column = [x for x in df_attn_weights.columns if 'prediction' in x]
    num_rows = math.floor(len(df_attn_weights)*ratio)
    if high_risk:
        df_attn_weights = df_attn_weights.nlargest(n=num_rows, columns=target_column, keep='first')
    else:
        df_attn_weights = df_attn_weights.nsmallest(n=num_rows, columns=target_column, keep='first')

    freq_dict = {}
    count_dict = {}
    weight_dict = {}
    for index, row in df_attn_weights.iterrows():
        for i in range(3):
            word_window = row['words_'+str(i)]
            word = re.search('\[(.*)\]', word_window)
            if word:
                word = word.group(1)
            else:
                continue
            if word in freq_dict:
                freq_dict[word] += row['attn_'+str(i)]
                count_dict[word] += 1
                weight_dict[word].append(row['attn_'+str(i)])
            else:
                freq_dict[word] = row['attn_' + str(i)]
                count_dict[word] = 1
                weight_dict[word] = [row['attn_' + str(i)]]

    master_list=[]
    for word in freq_dict:
        master_list.append([word, np.mean(weight_dict[word]), count_dict[word], freq_dict[word]])

    df_word_cloud_data = pd.DataFrame(master_list, columns=["Word", 'Avg_weight', 'Frequency', 'Avg_weight X Frequency'])
    print(df_word_cloud_data.dtypes)
    df_word_cloud_data.sort_values(by=['Avg_weight X Frequency'], ascending=False, inplace=True)
    print(df_word_cloud_data.head(5))
    datasetPath = os.path.join(save_dir, 'df_' + 'global_high_risk.csv' if high_risk else 'global_low_risk.csv')
    # df_word_cloud_data.to_csv(datasetPath, index=False)

    # lower max_font_size
    wordcloud = WordCloud(relative_scaling=0.5, prefer_horizontal=1, max_font_size=512, random_state=0, width=1920, height=1080, max_words=20, background_color='white', color_func=lambda *args, **kwargs: "black")
    wordcloud.generate_from_frequencies(freq_dict)

    imgname = 'global_high_risk.png' if high_risk else 'global_low_risk.png'
    wordcloud.to_file(os.path.join(img_directory, imgname))

def create_individual_wordclouds(model_dir, save_dir, high_risk=True, ratio=0.005):
    img_directory = os.path.join(save_dir, 'visualizations', 'individual')
    if not os.path.exists(img_directory):
        os.makedirs(img_directory)
    df_attn_weights = pd.read_csv(os.path.join(model_dir, 'df_attn.csv'))
    target_column = next(x for x in df_attn_weights.columns if 'prediction' in x)
    num_rows = math.floor(len(df_attn_weights)*ratio)
    if high_risk:
        df_attn_weights = df_attn_weights.nlargest(n=num_rows, columns=target_column, keep='first')
    else:
        df_attn_weights = df_attn_weights.nsmallest(n=num_rows, columns=target_column, keep='first')

    for index, row in df_attn_weights.iterrows():
        freq_dict = {}
        for i in range(50):
            word = row['words_'+str(i)]
            if word in freq_dict:
                freq_dict[word] += row['attn_'+str(i)]
            else:
                freq_dict[word] = row['attn_' + str(i)]
        wordcloud = WordCloud(relative_scaling=0.5, prefer_horizontal=1, max_font_size=512, random_state=0, width=1920,
                              height=1080, max_words=10, background_color='white', color_func=lambda *args, **kwargs: "black")
        wordcloud.generate_from_frequencies(freq_dict)
        imgname = "ICUSTAY_ID_{}_prediction_{}_label{}_risk_{}.png".format(row['ICUSTAY_ID'], row[target_column], row[next(x for x in df_attn_weights.columns if 'label' in x)], 'high' if high_risk else 'low')
        wordcloud.to_file(os.path.join(img_directory, imgname))
        # lower max_font_size

if __name__ == '__main__':
    """
        Evaluate the model on the test set.
    """
    torch.set_num_threads(4)
    # Load the parameters from json file
    args = parser.parse_args()
    json_path = os.path.join(args.config_dir, 'params.json')
    assert os.path.isfile(json_path), "No json configuration file found at {}".format(json_path)
    params = utils.Params(json_path)

    save_dir = params.visualizations_path
    # use GPU if available
    params.cuda = torch.cuda.is_available()
    # Set the logger
    job_name = "emb{}_lr{}_k{}_bs{}_f{}_dr{}_{}_{}".format(params.emb, params.learning_rate, params.kernels,
                                                           params.batch_size, params.filters, params.dropout,
                                                           params.model, params.task)
    # Create a new folder in parent_dir with unique_name "job_name"
    print(job_name)
    model_dir = os.path.join(params.save_path, 'fold' + str(params.fold), job_name)
    if not os.path.exists(model_dir):
        os.makedirs(model_dir)

    task_save_dir = os.path.join(save_dir, params.task, params.emb, 'fold' + str(params.fold))

    print('Creating high risk individual wordclouds...')
    create_individual_wordclouds(model_dir, task_save_dir)
    print('Creating low risk individual wordclouds...')
    create_individual_wordclouds(model_dir, task_save_dir, high_risk=False)
    print('Creating high risk global wordclouds...')
    create_global_wordcloud(model_dir, task_save_dir)
    print('Creating high risk global wordclouds...')
    create_global_wordcloud(model_dir, task_save_dir, high_risk=False)


from typing import List

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        low = 0
        high = len(nums) - 1

        while (low <= high):
            if (low == high):
                if (target == nums[low]):
                    return low
                if (target < nums[low]):
                    return low
                else:
                    return low + 1

            mid = (low + high) // 2
            midValue = nums[mid]

            if (midValue == target):
                return mid
            if (target < midValue):
                high = mid - 1
            else:
                low = mid + 1

        return low

def test(sln, nums, target):
    result = sln.searchInsert(nums, target)
    print(result)

if __name__ == "__main__":
    sln = Solution()
    # test(sln, [1,3,5,6], 5)
    # test(sln, [1,3,5,6], 2)
    # test(sln, [1,3,5,6], 7)
    # test(sln, [1,3,5,6], 0)
    test(sln, [1, 3], 0)


import json
import logging
import time

from PySide6.QtGui import QIcon
from PySide6.QtWidgets import QApplication

from gui.main_window import MainWindow

logging.basicConfig(filename='pony.log', level=logging.INFO,
                    format='%(created)f-%(asctime)s\n%(message)s\n')
logging.Formatter.converter = time.gmtime

app = QApplication()
app.setWindowIcon(QIcon('resources/hcc-dispo_klein.png'))

window = MainWindow(app)

screen_width, screen_height = app.primaryScreen().size().toTuple()

with open('config.json') as f:
    config_data = json.load(f)
if not config_data.get('screen_size'):
    config_data['screen_size'] = {}
config_data['screen_size']['width'], config_data['screen_size']['height'] = screen_width, screen_height
with open('config.json', 'w') as f:
    json.dump(config_data, f)

window.show()

app.exec()


from flask import Flask, render_template, request, url_for
import os
from joblib import dump, load
from sklearn.linear_model import LogisticRegressionCV, LogisticRegression
import pandas as pd
import string
from spacy.lang.en.stop_words import STOP_WORDS
from spacy.lang.en import English
import spacy

# Creating our tokenizer function
def spacy_tokenizer(sentence):
    # Create our list of punctuation marks
    punctuations = string.punctuation

    # Create our list of stopwords
    nlp = spacy.load('en_core_web_sm')
    stop_words = spacy.lang.en.stop_words.STOP_WORDS

    # Load English tokenizer, tagger, parser, NER and word vectors
    parser = English()
    # Creating our token object, which is used to create documents with linguistic annotations.
    mytokens = parser(sentence)

    # Lemmatizing each token and converting each token into lowercase
    mytokens = [ word.lemma_.lower().strip() if word.lemma_ != "-PRON-" else word.lower_ for word in mytokens ]

    # Removing stop words
    mytokens = [ word for word in mytokens if word not in stop_words and word not in punctuations ]

    # return preprocessed list of tokens
    return mytokens

def clean_text(text):
    # Removing spaces and converting text into lowercase
    return text.strip().lower()
#######
app = Flask(__name__)

@app.route('/')
def student():
    return render_template('index.html')

@app.route('/result',methods = ['POST', 'GET'])
def result():
    if request.method == 'POST':
        result = request.form
        print(result.to_dict())
        res = result.to_dict()
        s_in = clean_text(res["review"])
        s_in = " ".join(spacy_tokenizer(s_in))
        df = pd.Series([s_in])
        # load the model
        model = load('text_classifier.joblib')
        pred = model.predict(df)
        print(pred)
        if pred[0] == 1:
            data = {"Sentiment": "positive"}
        else:
            data = {"Sentiment": "Negative"}
        return render_template("result.html", data=data, result=result)
    if request.method == 'GET':
        return "<h3> nothing to show </h3>"

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


import pkgconfig
from Cython.Build import cythonize
from setuptools import Extension, setup

dep = "avro-c"
dep_version = ">=1.8.0"
if not pkgconfig.installed(dep, dep_version):
    raise Exception(f"{dep}{dep_version} not found")

avroc_pkg = pkgconfig.parse(dep)
extensions = cythonize([Extension("*", sources=["src/avroc/*.pyx"], **avroc_pkg)], language_level="3")
setup(ext_modules=extensions)


import requests
import tkinter as tk
from tkinter import ttk, messagebox
from PIL import Image, ImageTk
from io import BytesIO
import base64

class ImageFetcher:
    def __init__(self, root):
        self.root = root
        self.root.title('Image Fetcher')
        self.root.geometry('500x400')
        self.root.configure(bg='#FFFFFF')

        self.style = ttk.Style()
        self.style.configure('TFrame', background='#FFFFFF')
        self.style.configure('TButton', font=('Arial', 14), foreground='black')
        self.style.configure('TLabel', background='#FFFFFF', font=('Arial', 14))
        self.style.configure('Header.TLabel', font=('Arial', 18, 'bold'))

        self.header_frame = ttk.Frame(root)
        self.header_frame.pack(fill='x')

        self.header_label = ttk.Label(self.header_frame, text='QLDT Image Fetcher', style='Header.TLabel')
        self.header_label.pack(pady=10)

        self.main_frame = ttk.Frame(root)
        self.main_frame.pack(pady=10)

        self.id_label = ttk.Label(self.main_frame, text='Student ID:')
        self.id_label.grid(row=0, column=0, sticky='w')

        self.id_entry = ttk.Entry(self.main_frame)
        self.id_entry.grid(row=0, column=1, sticky='w')

        self.fetch_button = ttk.Button(self.main_frame, text='Fetch Image', command=self.fetch_image)
        self.fetch_button.grid(row=0, column=2, padx=10)

        self.image_label = ttk.Label(root)
        self.image_label.pack(pady=10)

    def fetch_image(self):
        student_id = self.id_entry.get()
        if not student_id:
            messagebox.showwarning('Warning', 'Please enter a student ID.')
            return

        headers = {
            'Content-Length': '0',
            'Accept': 'application/json, text/plain, */*',
            'idpc': '',  # fill in if necessary
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.88 Safari/537.36',
            'Content-Type': 'text/plain',
            'Origin': 'http://qldt.hanu.vn',
            'Referer': 'http://qldt.hanu.vn/',
            'Accept-Encoding': 'gzip, deflate',
            'Accept-Language': 'en-GB,en-US;q=0.9,en;q=0.8',
            'Cookie': 'ASP.NET_SessionId=gmh3t5xnr5snnggebvktlgoi',
            'Connection': 'close'
        }

        response = requests.post('http://qldt.hanu.vn/api/sms/w-locthongtinimagesinhvien', headers=headers, params={'MaSV': student_id})

        if response.status_code == 200:
            data = response.json()
            if data.get('result') == True:
                img_base64 = data.get('data', {}).get('thong_tin_sinh_vien', {}).get('image', '')
                if img_base64:
                    image_data = base64.b64decode(img_base64)
                    image = Image.open(BytesIO(image_data))
                    photo = ImageTk.PhotoImage(image)
                    self.image_label.config(image=photo)
                    self.image_label.image = photo
                else:
                    messagebox.showinfo('Info', 'Image not found for the provided ID.')
            else:
                messagebox.showerror('Error', 'An error occurred while fetching the image or no image found for the provided ID.')
        else:
            messagebox.showerror('Error', f'Request failed with status code {response.status_code}.')

root = tk.Tk()
app = ImageFetcher(root)
root.mainloop()


import base64
import hashlib
import time
import binascii
import base58
from enum import Enum

from bitcoin.wallet import P2PKHBitcoinAddress
from coincurve.utils import verify_signature
from yadacoin.contracts.asset import Asset
from yadacoin.core.collections import Collections
from yadacoin.core.config import get_config
from yadacoin.core.identity import Identity, PrivateIdentity
from yadacoin.core.transaction import (
    InvalidTransactionException,
    InvalidTransactionSignatureException,
    Output,
    Transaction,
)
from yadacoin.core.transactionutils import TU

class PayoutOperators(Enum):
    PERCENT = "percent"
    FIXED = "fixed"

class PayoutType(Enum):
    RECURRING = "recurring"
    ONE_TIME = "one_time"

class ContractTypes(Enum):
    CHANGE_OWNERSHIP = "change_ownership"
    NEW_RELATIONSHIP = "new_relationship"

class Contract:
    def __init__(self, version, expiry, contract_type, identity, creator):
        self.config = get_config()

        if not isinstance(version, int):
            self.report_init_error("version")

        if not isinstance(expiry, int):
            self.report_init_error("expiry")

        if contract_type not in [x.value for x in ContractTypes]:
            self.report_init_error("contract_type")

        if not creator or (
            not isinstance(creator, dict) and not isinstance(creator, str)
        ):
            self.report_init_error("creator")

        self.version = version
        self.expiry = expiry
        self.contract_type = contract_type
        self.identity = PrivateIdentity.from_dict(identity)
        self.creator = (
            Identity.from_dict(creator) if isinstance(creator, dict) else creator
        )

    def get_string(self, p):
        return "" if p is None else str(p)

    def report_init_error(self, member):
        raise Exception(f"Cannot instantiate contract with invalid {member}")

    @staticmethod
    def from_dict(contract):
        from yadacoin.contracts.affiliate import AffiliateContract
        from yadacoin.contracts.changeownership import ChangeOwnershipContract

        cls = None
        if contract.get("contract_type") == ContractTypes.NEW_RELATIONSHIP.value:
            cls = AffiliateContract
        elif contract.get("contract_type") == ContractTypes.CHANGE_OWNERSHIP.value:
            cls = ChangeOwnershipContract

        return cls(**contract)

    async def verify_input(self, trigger_txn):
        if await self.config.BU.is_input_spent(
            trigger_txn.transaction_signature,
            self.identity.public_key,
            inc_mempool=True,
        ):
            raise Exception("input is already spent by contract")

    async def verify(self, contract_txn, trigger_txn=None, mempool_txns=None):
        await getattr(self, f"verify_{self.proof_type}")(contract_txn, trigger_txn)

    async def verify_generation(self, block, generated_txn=None, mempool_txns=None):
        contract_txn = await generated_txn.get_generating_contract()
        if not contract_txn:
            raise Exception("Could not find corresponding smart contract")

        verify_hash = await generated_txn.generate_hash()

        if verify_hash != generated_txn.hash:
            raise InvalidTransactionException("transaction is invalid")

        try:
            result = verify_signature(
                base64.b64decode(generated_txn.miner_signature),
                hashlib.sha256(generated_txn.transaction_signature.encode())
                .hexdigest()
                .encode("utf-8"),
                bytes.fromhex(block.public_key),
            )
            if not result:
                raise Exception("Payout miner signature did not verify")
        except:
            raise InvalidTransactionSignatureException(
                "Payout miner signature did not verify"
            )

        if generated_txn.requested_rid != contract_txn.requested_rid:
            raise Exception("requested_rid does not match that of smart contract")

        await getattr(self, f"verify_{self.proof_type}")(contract_txn, generated_txn)

    async def get_funds(self, contract_txn):
        address = str(
            P2PKHBitcoinAddress.from_pubkey(
                bytes.fromhex(contract_txn.relationship.identity.public_key)
            )
        )
        async for txn in self.config.BU.get_wallet_unspent_transactions(
            address, no_zeros=True
        ):
            yield Transaction.from_dict(txn)

    @staticmethod
    async def get_smart_contract(transaction_obj):
        smart_contract_block = await get_config().mongo.async_db.blocks.find_one(
            {
                "transactions.requested_rid": transaction_obj.requested_rid,
                "transactions": {
                    "$elemMatch": {"relationship.smart_contract": {"$exists": True}}
                },
                "transactions": {
                    "$elemMatch": {"id": {"$ne": transaction_obj.transaction_signature}}
                },
                "transactions": {
                    "$elemMatch": {
                        "relationship.smart_contract.expiry": {
                            "$gt": get_config().LatestBlock.block.index
                        }
                    }
                },
            },
            sort=[("index", 1)],
        )
        if not smart_contract_block:
            return
        for smart_contract in smart_contract_block.get("transactions"):
            if (
                smart_contract.get("relationship")
                and isinstance(smart_contract.get("relationship"), dict)
                and Collections.SMART_CONTRACT.value in smart_contract["relationship"]
            ):
                smart_contract_obj = Transaction.from_dict(smart_contract)
                return smart_contract_obj

    async def expire(self, contract_txn):
        return await getattr(self, f"expire_{self.proof_type}")(contract_txn)


import os
import logging

class BaseConfig(object):
    DEBUG = False
    logging.getLogger("flask_ask").setLevel(logging.DEBUG)

class DevelopmentConfig(BaseConfig):
    DEBUG = False
    logging.getLogger("flask_ask").setLevel(logging.DEBUG)
    #ASK_APPLICATION_ID = "<add-your-application-id-here>"

class TestingConfig(BaseConfig):
    DEBUG = True
    logging.getLogger("flask_ask").setLevel(logging.DEBUG)
    ASK_VERIFY_REQUESTS = False # Don't verify whether the requests are from Alexa service

config = {
    "development": "goodbooks_config.DevelopmentConfig",
    "testing": "goodbooks_config.TestingConfig",
    "default": "goodbooks_config.DevelopmentConfig"
}

def configure_app(app):
    config_name = os.getenv('FLASK_CONFIGURATION', 'default')
    app.config.from_object(config[config_name])