import torch
import torch.nn as nn
import torch.nn.functional as F

#TODO: focal loss index over error
class FocalLoss(nn.Module):
    def __init__(self, gamma=0, alpha=None, size_average=True):
        super(FocalLoss, self).__init__()
        self.gamma = gamma
        self.alpha = alpha
        if isinstance(alpha,(float,int)): self.alpha = torch.Tensor([alpha,1-alpha])
        if isinstance(alpha,list): self.alpha = torch.Tensor(alpha)
        self.size_average = size_average

    def forward(self, input, target):
        if input.dim()>2:
            input = input.view(input.size(0),input.size(1),-1)  # N,C,H,W => N,C,H*W
            input = input.transpose(1,2)    # N,C,H*W => N,H*W,C
            input = input.contiguous().view(-1,input.size(2))   # N,H*W,C => N*H*W,C
        target = target.view(-1,1)

        logpt = F.log_softmax(input)
        logpt = logpt.gather(1,target)
        logpt = logpt.view(-1)
        pt = logpt.data.exp()

        if self.alpha is not None:
            if self.alpha.type()!=input.data.type():
                self.alpha = self.alpha.type_as(input.data)
            at = self.alpha.gather(0,target.data.view(-1))
            logpt = logpt * at

        loss = -1 * (1-pt)**self.gamma * logpt
        if self.size_average:
            return loss.mean()
        else:
            return loss.sum()

def multi_focal_loss_fusion(d0, d1, d2, d3, d4, d5, d6, labels_v):
    focal_loss = FocalLoss(size_average=True)

    loss0 = focal_loss(d0, labels_v)
    loss1 = focal_loss(d1, labels_v)
    loss2 = focal_loss(d2, labels_v)
    loss3 = focal_loss(d3, labels_v)
    loss4 = focal_loss(d4, labels_v)
    loss5 = focal_loss(d5, labels_v)
    loss6 = focal_loss(d6, labels_v)
    loss = loss0 + loss1 + loss2 + loss3 + loss4 + loss5 + loss6

    #print("l0: %3f, l1: %3f, l2: %3f, l3: %3f, l4: %3f, l5: %3f, l6: %3f\n"%(loss0.data.item(),loss1.data.item(),loss2.data.item(),loss3.data.item(),loss4.data.item(),loss5.data.item(),loss6.data.item()))

    return loss0, loss

def multi_bce_loss_fusion(d0, d1, d2, d3, d4, d5, d6, labels_v):
    bce_loss = nn.BCELoss(size_average=True)

    loss0 = bce_loss(d0, labels_v)
    loss1 = bce_loss(d1, labels_v)
    loss2 = bce_loss(d2, labels_v)
    loss3 = bce_loss(d3, labels_v)
    loss4 = bce_loss(d4, labels_v)
    loss5 = bce_loss(d5, labels_v)
    loss6 = bce_loss(d6, labels_v)
    loss = loss0 + loss1 + loss2 + loss3 + loss4 + loss5 + loss6

    #print("l0: %3f, l1: %3f, l2: %3f, l3: %3f, l4: %3f, l5: %3f, l6: %3f\n"%(loss0.data.item(),loss1.data.item(),loss2.data.item(),loss3.data.item(),loss4.data.item(),loss5.data.item(),loss6.data.item()))

    return loss0, loss

# def CB_loss(labels, logits, samples_per_cls, no_of_classes, loss_type, beta, gamma):
#     """Compute the Class Balanced Loss between `logits` and the ground truth `labels`.
#     Class Balanced Loss: ((1-beta)/(1-beta^n))*Loss(labels, logits)
#     where Loss is one of the standard losses used for Neural Networks.
#     Args:
#       labels: A int tensor of size [batch].
#       logits: A float tensor of size [batch, no_of_classes].
#       samples_per_cls: A python list of size [no_of_classes].
#       no_of_classes: total number of classes. int
#       loss_type: string. One of "sigmoid", "focal", "softmax".
#       beta: float. Hyperparameter for Class balanced loss.
#       gamma: float. Hyperparameter for Focal loss.
#     Returns:
#       cb_loss: A float tensor representing class balanced loss
#     """
#     effective_num = 1.0 - np.power(beta, samples_per_cls)
#     weights = (1.0 - beta) / np.array(effective_num)
#     weights = weights / np.sum(weights) * no_of_classes
#
#     labels_one_hot = F.one_hot(labels, no_of_classes).float()
#
#     weights = torch.tensor(weights).float()
#     weights = weights.unsqueeze(0)
#     weights = weights.repeat(labels_one_hot.shape[0],1) * labels_one_hot
#     weights = weights.sum(1)
#     weights = weights.unsqueeze(1)
#     weights = weights.repeat(1,no_of_classes)
#
#     if loss_type == "focal":
#         cb_loss = focal_loss(labels_one_hot, logits, weights, gamma)
#     elif loss_type == "sigmoid":
#         cb_loss = F.binary_cross_entropy_with_logits(input = logits,target = labels_one_hot, weights = weights)
#     elif loss_type == "softmax":
#         pred = logits.softmax(dim = 1)
#         cb_loss = F.binary_cross_entropy(input = pred, target = labels_one_hot, weight = weights)
#     return cb_loss


import numpy             as np
import mediapipe         as mp
import matplotlib.pyplot as plt

from utils import (
    poseDetector, poseUtils
)

def main():

    fileName = 'data/Question 19 - 8AE44065-F2F5-4D85-9A96-F69471837F7A.jpeg'
    image    = poseUtils.getImage(fileName)

    pDetector      = poseDetector.PoseDetector()
    results        = pDetector.getResults( image )
    annotatedImage = poseUtils.generateAnnotatedImage( image, results )

    print(results.segmentation_mask)
    print(results.segmentation_mask.shape)

    plt.figure()
    plt.imshow(image)

    plt.figure()
    plt.imshow(annotatedImage)
    plt.savefig('results/temp.png')

    return

if __name__ == '__main__':
    main()


from datetime import datetime, timedelta
from django.db import models
from django.db.models import Q
from django.contrib.postgres.fields import JSONField
from simple_history.models import HistoricalRecords
from web.sns import notify_productcategory_change
from web.managers import ArticleManager
from web.gs1_code_lists import Allergen, FishingZone, Origin, T3780

class Storage():
    TYPE = (
        ("Colonial", "Colonial"),
        ("Refrigerated", "Refrigerated"),
        ("Frozen", "Frozen"),
        ("Unspecified", "Unspecified")
    )

class Article(models.Model):

    TYPES = (
        ("BASE_UNIT_OR_EACH", "BASE_UNIT_OR_EACH"),
        ("CASE", "CASE"),
        ("1/4", "1/4"),
        ("1/2", "1/2"),
        ("PALLET", "PALLET")
    )

    VATS = [6.0, 12.0, 25.0]

    consumer_unit = models.BooleanField(
        default=False, verbose_name="Consumer unit",
        help_text="Should this article be available to consumers?")
    descriptor_code = models.CharField(
        choices=TYPES, max_length=64, verbose_name="Type",
        help_text="What type of article is this?")
    gtin = models.CharField(max_length=14, unique=True,
                            default=0, verbose_name="GTIN")
    child_gtin = models.CharField(
        blank=True, max_length=14, default="",
        verbose_name="Child GTIN",
        help_text="If this is a package, what GTIN does the package contain?")
    quantity_of_lower_layer = models.IntegerField(
        blank=True, default=0, verbose_name="Quantity of Lower Layer",
        help_text="How many of that GTIN does it contain?")
    category = models.CharField(
        max_length=100, verbose_name="Category",
        help_text="Industri category (GS1)")
    weight_g = models.FloatField(default=0, verbose_name="Weight (g)")
    height_mm = models.FloatField(default=0, verbose_name="Height (mm)")
    length_mm = models.FloatField(default=0, verbose_name="Length (mm)")
    width_mm = models.FloatField(default=0, verbose_name="Depth (mm)")
    volume_dm3 = models.FloatField(max_length=10, default=0,
                                   verbose_name="Volume (dm³)")
    net_content = models.FloatField(null=True, verbose_name="Net Content")
    net_content_unit_code = models.CharField(null=True,
                                             max_length=10, verbose_name="Net Content Unit Code", choices=list(T3780.UNIT_CODES.items()))
    creation_date = models.DateTimeField(verbose_name="Creation date")
    name = models.CharField(max_length=100, verbose_name="Name")
    description = models.TextField(blank=True, verbose_name="Description")
    recycle_fee = models.FloatField(default=0.0, verbose_name="Recycle Fee")
    last_modified = models.DateTimeField(
        auto_now=False, verbose_name="Last modified")
    brand_name = models.CharField(max_length=256, verbose_name="Brand")
    source = models.CharField(max_length=40, verbose_name="Source", blank=True)
    vat = models.FloatField(
        default=0, verbose_name="VAT", choices=zip([0.0] + VATS, [0.0] + VATS))
    adult_product = models.BooleanField(
        default=False, verbose_name="Adult Product")
    marketing_message = models.TextField(
        blank=True, verbose_name="Marketing message")
    nutrition_description = models.TextField(
        blank=True, verbose_name="Nutrition Description")
    ingredient_description = models.TextField(
        blank=True, verbose_name="Ingredient Description")
    allergen_statement = models.TextField(
        verbose_name="Allergen Statement", blank=True, default='')
    allergens = JSONField(
        verbose_name="Allergens", blank=True, default=dict)
    origin = models.IntegerField(
        blank=True, verbose_name="Origin", choices=Origin.COUNTRY, default=0)
    fishing_zone = models.IntegerField(
        blank=True, choices=FishingZone.AREA, default=0)
    whitelisted = models.BooleanField(
        default=False, verbose_name="Whitelisted")
    history = HistoricalRecords(
        excluded_fields=['creation_date', 'last_modified'])
    objects = ArticleManager()
    storage_type = models.CharField(
        max_length=64, choices=Storage.TYPE,
        default="Unspecified", verbose_name="Storage Type")
    storage_temperature_range = models.CharField(
        max_length=64, blank=True,
        default="", verbose_name="Storage Temperature Range")

    class Meta:
        indexes = [
            models.Index(fields=['category', 'name', 'gtin', 'source'])
        ]
        ordering = ['-id']

    def is_valid(self):
        if self.whitelisted or not self.consumer_unit:
            return True

        if (self.articleimage_set.count() > 0 and
                self.weight_g > 0 and
                self.height_mm > 0 and
                self.length_mm > 0 and
                self.width_mm > 0 and
                self.volume_dm3 > 0 and
                self.name != '' and
                self.brand_name != '' and
                self.marketing_message != '' and
                self.nutrition_description != '' and
                self.ingredient_description != ''):
            if ((self.consumer_unit and self.vat in Article.VATS) or
                    not self.consumer_unit):
                return True
        return False

    def get_allergens(self):
        allergen_list = []
        for allergen in self.allergens:
            allergen_list.append(
                Allergen.get_text(allergen)
            )
        return ", ".join(allergen_list)

    def save(self, *args, **kwargs):
        super(Article, self).save(*args, **kwargs)

        # Link unlinked images
        images = ArticleImage.objects.filter(
            article=None,
            gtin=self.gtin
        )

        for image in images:
            image.article = self
            image.save()

        # Save products to trigger validation check
        products = Product.objects.filter(article__gtin=self.gtin)
        for product in products:
            product.save_without_historical_record()

    def post_delete(sender, instance, using):
        products = Product.objects.filter(article__gtin=instance.gtin)
        for product in products:
            product.save_without_historical_record()

    def get_image(self):
        if self.descriptor_code == "PALLET":
            return "PALLET"

        if (self.descriptor_code in ["CASE", "1/4", "1/2"] and
                not self.consumer_unit):
            return "CASE"

        return self.articleimage_set.first()

    def get_related(self):
        related = self.get_related_rec()
        related = filter(lambda x: x.id != self.id, related)
        return sorted(related, key=lambda package: package.gtin)

    def get_related_rec(self, packages=[]):
        child = Article.objects.filter(gtin=self.child_gtin).first()
        parents = list(Article.objects.filter(child_gtin=self.gtin))

        if child is not None:
            parents.append(child)

        for p in parents:
            if p not in packages:
                packages.append(p)
                p.get_related_rec(packages)

        return packages

class ArticleImage(models.Model):
    gtin = models.CharField(max_length=14, default=0, verbose_name="GTIN")
    angle = models.CharField(max_length=6, blank=True, verbose_name="Angle")
    filename = models.CharField(max_length=256, verbose_name="Filename")
    creation_date = models.DateTimeField(auto_now_add=True,
                                         verbose_name="Created")
    source = models.CharField(max_length=40, verbose_name="Source", blank=True)
    history = HistoricalRecords(excluded_fields=['creation_date'])
    article = models.ForeignKey(Article, on_delete=models.DO_NOTHING,
                                blank=True, null=True)
    last_modified = models.DateTimeField(auto_now=True, blank=True,
                                         verbose_name='Last Modified')

    def save(self, *args, **kwargs):
        if (self.article is None and
                Article.objects.filter(gtin=self.gtin).exists()):
            article = Article.objects.get(gtin=self.gtin)
            self.article = article

        super(ArticleImage, self).save(*args, **kwargs)

class ProductCategory(models.Model):
    name = models.CharField(max_length=128,
                            verbose_name='Category Name', unique=True)
    parentcategory = models.ForeignKey("self",
                                       null=True, blank=True,
                                       on_delete=models.DO_NOTHING,
                                       verbose_name='Parent Category')
    url = models.CharField(max_length=256, verbose_name='Category URL')
    is_public = models.BooleanField(verbose_name='Is Public')
    introduction = models.TextField(verbose_name='Intro')
    title = models.CharField(max_length=256, verbose_name='Title')
    metadescription = models.CharField(max_length=1024,
                                       null=True,
                                       blank=True,
                                       verbose_name='Meta Description')
    removed_date = models.DateTimeField(null=True,
                                        blank=True,
                                        verbose_name='Removed')
    creation_date = models.DateTimeField(auto_now_add=True,
                                         verbose_name='Created')
    last_modified = models.DateTimeField(auto_now=True, blank=True,
                                         verbose_name='Last Modified')

    tags = models.ManyToManyField(
        'Tag', related_name='categories', blank=True)

    class Meta:
        ordering = ['-id']

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        notify_productcategory_change(self)
        super(ProductCategory, self).save()

class MerchantArticle(models.Model):
    article_gtin = models.CharField(null=True, max_length=14,
                                    verbose_name="Article GTIN")
    article = models.ForeignKey(
        Article, null=True, blank=True, on_delete=models.DO_NOTHING,
        related_name='merchant_articles')
    merchant_name = models.CharField(
        max_length=256, verbose_name='Merchant name')
    external_id = models.CharField(max_length=256, verbose_name='External ID')
    availability_status = models.CharField(
        max_length=100, default='', verbose_name='Availability status')
    listed = models.CharField(max_length=20, blank=True, verbose_name='Listed')
    last_date_to_order = models.CharField(
        max_length=20, blank=True, verbose_name='Last date to order')
    price = models.FloatField(max_length=10, default=0, verbose_name="Price")
    currency = models.CharField(max_length=5, default="SEK", verbose_name="Currency")
    sales_price = models.FloatField(max_length=10, default=0, verbose_name="Sales Price")
    sales_price_valid_from = models.CharField(
        max_length=20, blank=True, verbose_name='Sales Price Valid From')
    sales_price_valid_to = models.CharField(
        max_length=20, blank=True, verbose_name='Sales Price Valid To')

    creation_date = models.DateTimeField(
        auto_now_add=True, verbose_name='Creation date')
    last_modified = models.DateTimeField(
        auto_now=True, verbose_name='Last modified')
    history = HistoricalRecords(excluded_fields=['creation_date',
                                                 'last_modified'])

    class Meta:
        unique_together = (("external_id", "merchant_name"))
        ordering = ['-id']

    def save(self, *args, **kwargs):
        self.article = Article.objects.filter(gtin=self.article_gtin).first()
        super(MerchantArticle, self).save(*args, **kwargs)
        if self.article:
            self.save_related_products()

    def post_delete(sender, instance, using):
        products = Product.objects.filter(article__gtin=instance.article.gtin)
        for product in products:
            product.save_without_historical_record()

    def save_related_products(self):
        products = Product.objects.filter(article__gtin=self.article.gtin)
        for product in products:
            product.save_without_historical_record()

    def __str__(self):
        return self.external_id + " (" + self.merchant_name + ")"

class Product(models.Model):
    TYPES = (
        ("Normal", "Normal"),
        ("Crossdocking", "Crossdocking"),
        ("Nightorder", "Nightorder"),
    )

    marketing_message = models.TextField(blank=True)
    nutrition_description = models.TextField(blank=True)
    ingredient_description = models.TextField(blank=True)
    name = models.CharField(max_length=256, blank=True)
    brand_name = models.CharField(max_length=256, verbose_name="Brand",
                                  blank=True)
    description = models.TextField(blank=True, verbose_name="Description")
    creation_date = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    product_id = models.BigIntegerField(default=0, unique=True)
    article = models.ForeignKey(Article, on_delete=models.DO_NOTHING)
    prefered_merchantarticle = models.ForeignKey(
        MerchantArticle, on_delete=models.DO_NOTHING,
        blank=True, null=True, default=None)
    product_category = models.ForeignKey(
        ProductCategory, on_delete=models.DO_NOTHING, blank=True, null=True)
    tags = models.ManyToManyField(
        'Tag', related_name='products', blank=True)
    adult_product = models.BooleanField(
        default=False, verbose_name="Adult Product")
    origin = models.IntegerField(blank=True,
                                 verbose_name="Origin",
                                 choices=Origin.COUNTRY,
                                 default=0)
    fishing_zone = models.IntegerField(blank=True,
                                       choices=FishingZone.AREA,
                                       default=0)
    allergen_statement = models.TextField(
        verbose_name="Allergen Statement", blank=True, default='')
    allergens = JSONField(
        verbose_name="Allergens", blank=True, default=dict)
    weight_g = models.FloatField(
        blank=True, null=True, verbose_name="Weight (g)")
    height_mm = models.FloatField(
        blank=True, null=True, verbose_name="Height (mm)")
    length_mm = models.FloatField(
        blank=True, null=True, verbose_name="Length (mm)")
    width_mm = models.FloatField(
        blank=True, null=True, verbose_name="Depth (mm)")
    volume_dm3 = models.FloatField(
        max_length=10, blank=True, null=True, verbose_name="Volume (dm³)")
    net_content = models.FloatField(
        blank=True, null=True, verbose_name="Net Content")
    net_content_unit_code = models.CharField(
        blank=True, null=True, max_length=10, verbose_name="Net Content Unit Code", choices=list(T3780.UNIT_CODES.items()))
    recycle_fee = models.FloatField(default=0.0, verbose_name="Recycle Fee")
    vat = models.FloatField(
        default=0, verbose_name="VAT",
        choices=zip([0.0] + Article.VATS, [0.0] + Article.VATS))
    last_receipt_day = models.IntegerField(blank=True, default=0)
    last_sales_day = models.IntegerField(blank=True, default=0)
    product_type = models.CharField(
        max_length=128, blank=True, choices=TYPES,
        default="Normal", verbose_name="Type")
    valid_weight = models.BooleanField(blank=True, default=False)
    valid_volume = models.BooleanField(blank=True, default=False)
    valid_image = models.BooleanField(blank=True, default=False)
    valid_brand = models.BooleanField(blank=True, default=False)
    valid_price = models.BooleanField(blank=True, default=False)
    valid_merchantarticle = models.BooleanField(blank=True, default=False)
    history = HistoricalRecords(
        excluded_fields=['creation_date', 'last_modified'])
    valid_products_query = Q(
        # valid_weight=True,
        # valid_volume=True,
        valid_image=True,
        valid_brand=True,
        valid_price=True,
        # valid_merchantarticle=True,
        article__vat__in=Article.VATS)

    class Meta:
        indexes = [
            models.Index(fields=['product_id', 'name', 'brand_name'])
        ]
        ordering = ['-id']

    def validate_weight(self):
        packages = self.article.get_related()
        case = list(filter(
            lambda package: package.descriptor_code == 'CASE',
            packages
        ))

        if len(case) == 0:
            self.valid_weight = False
            return self.valid_weight
        else:
            case = case[0]

            if int(case.weight_g) == 0:
                self.valid_weight = False
                return self.valid_weight

            weight = self.weight_g or self.article.weight_g
            weight_diff = (
                weight *
                case.quantity_of_lower_layer /
                case.weight_g - 1) * 100

            if abs(weight_diff) >= 20.0:
                self.valid_weight = False
                return self.valid_weight

        self.valid_weight = True
        return self.valid_weight

    def validate_volume(self):
        packages = self.article.get_related()
        case = list(filter(
            lambda package: package.descriptor_code == 'CASE',
            packages
        ))

        if len(case) == 0:
            self.valid_volume = False
            return self.valid_volume
        else:
            case = case[0]

            if int(case.volume_dm3) == 0:
                self.valid_volume = False
                return self.valid_volume

            volume = self.volume_dm3 or self.article.volume_dm3
            volume_diff = (
                volume *
                case.quantity_of_lower_layer /
                case.volume_dm3 - 1) * 100

            if abs(volume_diff) >= 20.0:
                self.valid_volume = False
                return self.valid_volume

        self.valid_volume = True
        return self.valid_volume

    def validate_image(self):
        if self.productimage_set.count() == 0:
            self.valid_image = False
            return self.valid_image

        self.valid_image = True
        return self.valid_image

    def validate_brand(self):
        if self.brand_name == '' and self.article.brand_name == '':
            self.valid_brand = False
            return self.valid_brand

        self.valid_brand = True
        return self.valid_brand

    def validate_price(self):
        store_ids_to_check = {10, 14, 16}
        store_ids_with_price = set(
            self
            .product_detail
            .filter(price__gt=0)
            .values_list('store',  flat=True)
        )

        store_ids_missing_price = store_ids_to_check - store_ids_with_price

        if len(store_ids_missing_price) > 0:
            self.valid_price = False
            return self.valid_price

        self.valid_price = True
        return self.valid_price

    def validate_merchantarticle(self):
        orderable = True
        if self.article.merchant_articles.count() == 0:
            orderable = False
            packages = self.article.get_related()
            for package in packages:
                if package.merchant_articles.count() > 0:
                    orderable = True
                    break

        self.valid_merchantarticle = orderable
        return self.valid_merchantarticle

    def validate_all(self):
        self.validate_weight()
        self.validate_volume()
        self.validate_image()
        self.validate_brand()
        self.validate_price()
        self.validate_merchantarticle()

    def save(self, *args, **kwargs):
        self.validate_all()
        super(Product, self).save(*args, **kwargs)

    def get_allergens(self):
        allergen_list = []
        for allergen in self.allergens:
            allergen_list.append(
                Allergen.get_text(allergen)
            )
        return ", ".join(allergen_list)

class ProductImage(models.Model):
    angle = models.CharField(max_length=6, blank=True, verbose_name="Angle")
    filename = models.CharField(max_length=256, verbose_name="Filename")
    creation_date = models.DateTimeField(auto_now_add=True,
                                         verbose_name="Created")
    source = models.CharField(max_length=40, verbose_name="Source", blank=True)
    history = HistoricalRecords(excluded_fields=['creation_date'])
    product = models.ForeignKey(Product, on_delete=models.CASCADE, blank=True,
                                null=True)
    active = models.BooleanField(default=True)
    main = models.BooleanField(default=False)

    class Meta:
        ordering = ['-main', '-creation_date']

    def save(self, *args, **kwargs):
        super(ProductImage, self).save(*args, **kwargs)

        if self.product is not None:
            self.product.save_without_historical_record()

    def post_delete(sender, instance, using):
        if instance.product is not None:
            instance.product.save_without_historical_record()

class ProductDetail(models.Model):
    STORES = (
        (10, "Stockholm"),
        (14, "Göteborg"),
        (16, "Malmö")
    )

    STATUSES = (
        (1, "Open"),
        (2, "Out of stock"),
        (3, "Replacement"),
        (4, "Missing info"),
        (5, "Sample")
    )

    store = models.IntegerField(choices=STORES)
    price = models.FloatField(max_length=10, default=0)
    enabled = models.BooleanField()
    first_enabled = models.DateTimeField(blank=True, null=True)
    status = models.IntegerField(choices=STATUSES, default=4)
    orderfactor = models.BooleanField(
        default=False, verbose_name="Orderfactor")
    product = models.ForeignKey(Product, on_delete=models.DO_NOTHING,
                                related_name='product_detail')
    prefered_merchantarticle = models.ForeignKey(
        MerchantArticle, on_delete=models.DO_NOTHING,
        blank=True, null=True, default=None)
    history = HistoricalRecords()

    def save(self, *args, **kwargs):
        super(ProductDetail, self).save(*args, **kwargs)

        if self.product is not None:
            self.product.save_without_historical_record()

    def post_delete(sender, instance, using):
        if instance.product is not None:
            instance.product.save_without_historical_record()

    def is_tagged_as_new(self):
        if self.first_enabled is None:
            return False

        cutoff_date = datetime.now(
            self.first_enabled.tzinfo) - timedelta(days=30)

        return self.first_enabled > cutoff_date

class Tag(models.Model):
    name = models.CharField(max_length=200, unique=True, verbose_name="Name")

    def __str__(self):
        return self.name

    class Meta:
        ordering = ['-id']


from struct import pack, unpack
import logging

from handleclient import common
from handleclient import utils
from handleclient import message
from handleclient import handlevalue

from handleclient.handlevalue import HandleValue
from handleclient.message import Message, Envelope, Header, Body, Credential

logger = logging.getLogger(__name__)
logger.setLevel(common.LOG_LEVEL)
logger.addHandler(common.ch)

class ErrorResponseBody(Body):
    def __init__(self):
        self.errMsg = ""

    @classmethod
    def parse(self, body):
        assert isinstance(body, bytes)
        self.errMsg = utils.uba(body)
        assert 4 + len(self.errMsg) == len(body)

    def __str__(self):
        res = ""
        res += f"{self.errMsg}"
        return res

class ReferralResponseBody(Body):
    """https://tools.ietf.org/html/rfc3652#section-3.4
    """
    def __init__(self):
        self.valueList = []

    @classmethod
    def parse(self, body):
        assert isinstance(body, bytes)
        logger.debug(body[:])

        offset = 0
        self.valueCnt = utils.u32(body[offset:])
        offset += 4
        for _i in range(self.valueCnt):
            pass

    # def __str__(self):
    #     res = ""
    #     res += f"{self.errMsg}\n"
    #     return res

class SomeResponseBody(Body):
    def __init__(self):
        pass

    @classmethod
    def parse(self, body):
        assert isinstance(body, bytes)
        logger.warning("todo")

    def __str__(self):
        res = ""
        res += "unimplemented"
        return res


# Name: John Kelly
# ID: C00176932

from flask import Flask, render_template, request, session
from operator import itemgetter
from collections import Counter
import pickle
import random
import time
import os.path
import parse_words

app = Flask(__name__)

@app.route('/')
def start_app():
    if os.path.isfile('pickle/source_words.pickle'):
        with open('pickle/source_words.pickle', 'rb') as ph:
            source_words = pickle.load(ph)
    else:
        parse_words.create_selected_word_dictionary()
    session.setdefault('selected_word', '')
    session.setdefault('current_user', {})
    session['selected_word'] = random.choice(source_words)
    session['current_user']['start_time'] = time.time() * 1000
    return render_template('entries.html',
                                    title=session['selected_word'] + ' | Word Game')

@app.route('/checkscore', methods=['POST'])
def process_the_data():
    session['current_user']['end_time'] = time.time() * 1000
    session.setdefault('user_input', {})
    session['user_input'] = request.form.to_dict()
    valid_word = validate_input_duplicates(session['user_input'])

    if valid_word:
        valid_word, session['user_input'] = validate_input(session['user_input'], session['selected_word'])

    if valid_word is False:
        return render_template('wrong_results.html',
                                        sourceWord=session['selected_word'],
                                        words=session['user_input'])

    session['current_user']['total_time'] = session['current_user']['end_time'] -session['current_user']['start_time']
    return render_template('right_answer.html')

@app.route('/topscorerslist', methods=['POST'])
def join_the_scoreboard():
    user_input = request.form.to_dict()
    if os.path.isfile('pickle/top_scorers_list.pickle'):
        with open('pickle/top_scorers_list.pickle', 'rb') as ph:
            top_scorers_list = pickle.load(ph)
    else:
        top_scorers_list = []
    session['current_user']['name'] = user_input['name']
    session['current_user']['display_time'] = calculate_display_time(session['current_user']['total_time'])
    top_scorers_list.append(session['current_user'])
    with open('pickle/top_scorers_list.pickle', 'wb') as ph:
        pickle.dump(top_scorers_list, ph)
    sorted_list = sorted(top_scorers_list, key=itemgetter('total_time', 'start_time'), reverse=False)

    return render_template('top_ten.html',
                                    words=session['user_input'],
                                    selected_word=session['selected_word'],
                                    top_ten_scorers=sorted_list[:10],
                                    position=sorted_list.index(session['current_user']) + 1)

def validate_input(user_input, selected_word):
    valid_word = True
    for user_input_key, user_input_value in user_input.items():
        if validate_input_length(user_input_value) and validate_input_characters(user_input_value.lower(), selected_word) and validate_input_in_dictionary(user_input_value) and user_input_value != selected_word:
            user_input[user_input_key] = {
                'word': user_input_value,
                'color': 'green'
            }
        else:
            if ' ' in user_input_value:
                user_input[user_input_key] = {
                    'word': "Spaces aren't allowed",
                    'color': 'orange'
                }
            else:
                user_input[user_input_key] = {
                    'word': user_input_value,
                    'color': 'red'
                }
            valid_word = False

    return valid_word, user_input

def validate_input_length(word):
    return len(word) > 2

def validate_input_characters(word, selected_word):
    valid_word = True
    s = Counter(selected_word)
    w = Counter(word)
    for letter in word:
        if letter not in selected_word or w[letter] > s[letter]:
            valid_word = False
    return valid_word

def validate_input_duplicates(all_values):
    return len(set(all_values)) == 7

def validate_input_in_dictionary(word):
    if os.path.isfile('pickle/dictionary.pickle'):
        with open('pickle/dictionary.pickle', 'rb') as ph:
            dictionary = pickle.load(ph)
    else:
        parse_words.create_dictionary()
    return word in dictionary

def calculate_display_time(milliseconds):
    seconds = int((session['current_user']['total_time'] / 1000) % 60)
    minutes = int((session['current_user']['total_time'] / (1000*60)) % 60)
    hours   = int((session['current_user']['total_time'] / (1000*60*60)) % 24)
    return str(hours) + ':' + str(minutes) + ':' + str(seconds)

if __name__ == '__main__':
    app.config['SECRET_KEY'] = 'THISISMYSECRETKEY'
    app.run(debug=True)


import cv2
import matplotlib.pyplot as plt
import os
from glob import glob
import numpy as np
import argparse

parser = argparse.ArgumentParser()
parser.add_argument( "--root",   type=str,   default="./atten_bear_visualization/",  help="down or middle or up" )
parser.add_argument( "--num_sample", type=int,   default=3,  help="number of samples generated in the ldm model" )
parser.add_argument( "--num_level", type=int,   default=4,  help="(8, 16, 32, 64)" )
parser.add_argument( "--num_att_comp", type=int,   default=3,  help="down, up, down&up =3" )
parser.add_argument( "--num_att_maps", type=int,   default=10,  help="number of attnetion maps generated in the model." )
parser.add_argument( "--token_idx", type=int,   default=1,  help="number of samples generated in the ldm model" )
args = parser.parse_args()

root = args.root
num_sample = args.num_sample
num_level = args.num_level    # (8, 16, 32, 64)
num_att_comp = args.num_att_comp #level= 00,22,02
num_att_maps = args.num_att_maps

imgs = sorted(glob( os.path.join(root, "*.png") ))#os.listdir(root)

attmap_list = []
bundle_list = []

""" 1. bundle image 읽어오는 과정 """
cur_idx = num_sample*num_att_maps #i*num_att_maps + k +1
for m in range(cur_idx, cur_idx+num_att_maps):
    if m == cur_idx:
        h,w,c = cv2.imread(imgs[m]).shape
        white_img = np.ones((h, h*num_sample, 3))*255

    bundle_list.append( cv2.resize(cv2.imread(imgs[m]), (h*num_sample,h)) ) # (516, 1548, 3)

""" 2. attention map 읽어오는 과정 """
for i in range(num_sample): # num_sample
    for k in range(num_att_maps): # num attention maps in each sample
            attmap_list.append(  cv2.resize(cv2.imread(imgs[i*num_att_maps + k]), (h,h))  )

""" 3. make bundle composition """
last_bundle = None
for mm in range(num_level):
    if mm==0:
        init_bundle = np.concatenate( ( bundle_list[mm], white_img, white_img), axis=1 )
    else:
        cur_idx = mm*num_att_comp-(num_sample-1)
        cur_bundle = np.concatenate( bundle_list[ cur_idx : cur_idx+num_att_comp ], axis=0 ) # down, downup, up
        if last_bundle is None:
            last_bundle = cur_bundle
        else:
            last_bundle = np.concatenate( (last_bundle, cur_bundle), axis=1 )
last_bundle = np.concatenate( (init_bundle, last_bundle), axis=0 )
cv2.imwrite( os.path.join(root, "./last_bundle_imgs_idx:{0}.png".format(args.token_idx)  ), last_bundle)

""" 4. make attenmap composition
0: 0 10 20
1: 1 11 21/ 2 12 22 /3 13 23
2: 4 14 24 /5 15 25 /6 16 26
....
"""
last_bundle = None
for r in range(num_level): # 4
    cur_att_map_list = []
    if r ==0:
        for i in range(num_sample): # 3
            cur_attmap = attmap_list[i*num_att_maps]
            cur_att_map_list.append(cur_attmap)
        cur_att_map_list = np.concatenate(cur_att_map_list, axis=1)

        white_img = np.ones((h, h*num_sample*2, 3))*255
        init_bundle = np.concatenate( (cur_att_map_list, white_img), axis=1 )
    else:
        cur_idx = r*(num_level-1)-(num_sample-1) #-2
        for i in range(num_sample): # 3
            cur_subatt_map_list = []
            for j in range(num_sample):
                cur_attmap  = attmap_list[i+cur_idx + j*num_att_maps]
                cur_subatt_map_list.append(cur_attmap)
            cur_att_map_list.append( np.concatenate(cur_subatt_map_list, axis=1) )

        cur_bundle = np.concatenate( cur_att_map_list, axis=0 )#.reshape(h*num_sample, h*num_sample, 3)

        if last_bundle is None:
            last_bundle = cur_bundle
        else:
            last_bundle = np.concatenate( (last_bundle, cur_bundle), axis=1 )
last_bundle = np.concatenate( (init_bundle, last_bundle), axis=0 )
cv2.imwrite( os.path.join(root, "./last_bundle_attnmaps_idx:{0}.png".format(args.token_idx)), last_bundle)


import argparse
import time
import absim.world as world

from absim.bayesian_agent import BayesianAgent
from absim.prob_agent import ProbAgent
from absim.prox_agent import ProxAgent
from absim.prob_prox_agent import ProbProxAgent
from absim.salesman_agent import SalesmanAgent

agent_lookup = {
    "prob" : ProbAgent,
    "prox" : ProxAgent,
    "prob_prox" : ProbProxAgent,
    "salesman" : SalesmanAgent,
    "bayes" : BayesianAgent
}

def parse_world(fname):
    """Parses a scavenger hunt world from a datfile.

    Parameters
    ----------
    fname : str
        source file name

    Returns
    -------
    world.World
        finalized scavenger hunt world
    list of str
        scavenger hunt
    str
        start location name
    """
    src = open(fname, "r")
    sec = None
    start_loc = None
    conns = []  # 3-tuples (from, to, cost)
    nodes = {}  # User-specified loc names -> integer IDs
    node_count = 0
    distrs = []
    hunt = []

    for line in src.readlines():
        # Blank lines and comments
        line = line.strip()
        if len(line) == 0 or line[0] == '#':
            continue

        # Section header line
        if line[0] == '[':
            sec = line[1:line.find(']')]
            continue

        # Map section
        if sec == "map":
            args = line.split()
            assert len(args) == 3
            n_from, n_to = args[0], args[1]

            # Parse for starting location
            if '*' in n_from:
                n_from = n_from.replace('*', '')
                if start_loc is None:
                    start_loc = n_from
            elif '*' in n_to:
                n_to = n_to.replace('*', '')
                if start_loc is None:
                    start_loc = n_to

            cost = float(args[2])
            if n_from not in nodes:
                nodes[n_from] = node_count
                node_count += 1
            if n_to not in nodes:
                nodes[n_to] = node_count
                node_count += 1
            conns.append((n_from, n_to, cost))
        # Distribution section
        elif sec == "distr":
            args = line.split()
            assert len(args) > 2
            obj = args[0]
            events = []
            ind = 1

            if obj not in hunt:
                hunt.append(obj)

            while ind < len(args):
                locs = []
                prob_ind = ind
                while args[prob_ind] in nodes:
                    locs.append(nodes[args[prob_ind]])
                    prob_ind += 1
                prob_arg = args[prob_ind]
                if '/' in prob_arg:
                    frac = prob_arg.split('/')
                    prob = float(frac[0]) / float(frac[1])
                else:
                    prob = float(prob_arg)
                events.append(world.Event(obj, locs, prob))
                ind = prob_ind + 1

            distrs.append(world.Distribution(events))
        else:
            assert False

    src.close()

    # Build graph
    g = world.Graph(node_count)
    for conn in conns:
        id_from, id_to, cost = nodes[conn[0]], nodes[conn[1]], conn[2]
        g.connect(id_from, id_to, cost)
        g.name_ids[conn[0]] = id_from
        g.name_ids[conn[1]] = id_to
    g.finalize()

    # Build world
    w = world.World(g, distrs)
    w.finalize()

    return w, hunt, start_loc

def simulate(world, hunt, start_loc, args):
    """Runs one or more scavenger hunts.

    Parameters
    ----------
    world : world.World
        scavenger hunt world
    hunt : list of str
        objects to find
    start_loc : str
        starting node name
    args : Namespace
        cmdline args parsed by argparse

    Returns
    -------
    float
        average distance traveled across all trials
    """
    total_distance = 0
    total_runtime = 0
    trials = args.trials
    agent = agent_lookup[args.agent](world, hunt, world.node_id(start_loc))
    agent.epoch()

    if not args.suppress:
        print(">>> Running %s trials of %s" % \
            (trials, agent.__class__.__name__))

    for i in range(trials):
        t_start, t_end = None, None
        world.populate()
        agent.setup()
        t_start = time.time()
        while not agent.done():
            agent.objs_at_loc = world.objs_at(agent.loc)
            agent.run()
        t_end = time.time()
        total_distance += agent.travel_distance
        total_runtime += t_end - t_start
        if not args.suppress:
            print("Progress: {:2.1%}".format(i / trials), end="\r")

    avg_distance = total_distance / trials
    avg_runtime = total_runtime / trials
    if not args.suppress:
        print("Average distance: %s" % avg_distance)
        if args.runtime:
            print("Average runtime: %ss" % avg_runtime)

    return avg_distance

if __name__ == "__main__":
    # Parse cmdline args
    ap = argparse.ArgumentParser()
    ap.add_argument("datfile", help="scavenger hunt world file", type=str)
    ap.add_argument("agent", help="algorithm to run", type=str)
    ap.add_argument("-t", "--trials", help="number of trials to run", type=int,
        default=1)
    ap.add_argument("-s", "--suppress", help="silence output",
        action='store_true')
    ap.add_argument("-r", "--runtime", help="show average runtime",
        action='store_true')
    args = ap.parse_args()

    # Generate scavenger hunt problem and simulate
    world, hunt, start_loc = parse_world(args.datfile)
    simulate(world, hunt, start_loc, args)


from typing import List

# Definition for a Node.
class Node:
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children if children is not None else []

class Solution:
    def findRoot(self, tree: List['Node']) -> 'Node':
        if len(tree) == 0:
            return None
        all_children = set()
        vals = {}
        for node in tree:
            vals[node.val] = node
            for child in node.children:
                all_children.add(child.val)
        for v, n in vals.items():
            if v not in all_children:
                return n
        return None


# Title: 우수 마을
# Link: https://www.acmicpc.net/problem/1949

import sys
from collections import defaultdict

sys.setrecursionlimit(10 ** 6)

read_single_int = lambda: int(sys.stdin.readline().strip())
read_list_int = lambda: list(map(int, sys.stdin.readline().strip().split(' ')))

def get_max(vil: int, select: int, dp: list, edges: defaultdict, popls: list, p_node: int):
    if dp[vil][select] != -1:
        return dp[vil][select]

    ans = popls[vil] if select else 0

    for child in edges[vil]:
        if child == p_node:
            continue
        if select:
            ans += get_max(child, 0, dp, edges, popls, vil)
        else:
            ans += max(get_max(child, 0, dp, edges, popls, vil), get_max(child, 1, dp, edges, popls, vil))

    dp[vil][select] = ans
    return ans

def solution(n: int, popls: list, edges: defaultdict):
    dp = [[-1 for _ in range(2)] for _ in range(n+1)]
    return max(get_max(1, 0, dp, edges, popls, 0), get_max(1, 1, dp, edges, popls, 0))

def main():
    n = read_single_int()
    popls = [0] + read_list_int()
    edges = defaultdict(lambda: [])
    for _ in range(n-1):
        a, b = read_list_int()
        edges[a].append(b)
        edges[b].append(a)
    print(solution(n, popls, edges))

if __name__ == '__main__':
    main()


import ply.lex as lex
from ply.lex import TOKEN

class Lexer:
    tokens = (
        "WORD",
        "APOSTROPH",
        "NEWLINE",
        "OTHERS",
    )

    large_alpha = "[ΑἈἌᾌἊᾊἎᾎᾈἉἍᾍἋᾋᾋἏᾉΆᾺᾼ]"
    large_epsilon = "[ΕἘἜἚἙἝἛΈῈ]"
    large_eta = "[ΗἨἬᾜἪᾚἮᾞᾘἩἭᾝἫᾛᾛἯᾙΉῊῌ]"
    large_iota = "[ΙἸἼἺἾἹἽἻἿΊῚΪ]"
    large_omicron = "[ΟὈὌὊὉὍὋΌῸ]"
    large_upsilon = "[ΥὙὝὛὟΎῪΫ]"
    large_omega = "[ΩὨὬᾬὪᾪὮᾮᾨὩὭᾭὫᾫᾫὯᾩΏῺῼ]"
    large_rho = "[ΡῬ]"
    large_consonant = "[ΒΓΔΖΘΚΛΜΝΞΠΣΤΦΧΨ]"

    small_alpha = "[αἀἄᾄἂᾂἆᾆᾀἁἅᾅἃᾃᾃἇᾁάᾴὰᾲᾶᾷᾳ]"
    small_epsilon = "[εἐἔἒἑἕἓέὲ]"
    small_eta = "[ηἠἤᾔἢᾒἦᾖᾐἡἥᾕἣᾓᾓἧᾑήῄὴῂῆῇῃ]"
    small_iota = "[ιἰἴἲἶἱἵἳἷίὶῖϊΐῒῗ]"
    small_omicron = "[οὀὄὂὁὅὃόὸ]"
    small_upsilon = "[υὐὔὒὖὑὕὓὗύὺῦϋΰῢῧ]"
    small_omega = "[ωὠὤᾤὢᾢὦᾦᾠὡὥᾥὣᾣᾣὧᾡώῴὼῲῶῷῳ]"
    small_rho = "[ρῤῥ]"
    small_consonant = "[βγδζθκλμνξπσςτφχψ]"

    alphabet = "(" + large_alpha + \
                "|" + large_epsilon + \
                "|" + large_eta + \
                "|" + large_iota + \
                "|" + large_omicron + \
                "|" + large_upsilon + \
                "|" + large_omega + \
                "|" + large_rho + \
                "|" + large_consonant + \
                "|" + small_alpha + \
                "|" + small_epsilon + \
                "|" + small_eta + \
                "|" + small_iota + \
                "|" + small_omicron + \
                "|" + small_upsilon + \
                "|" + small_omega + \
                "|" + small_rho + \
                "|" + small_consonant + ")"

    apostroph = "'"

    word = alphabet + "+" \
            + "(" + apostroph + alphabet + "*" + ")?"

    @TOKEN(word)
    def t_WORD(self, t):
        return t

    def t_NEWLINE(self, t):
        "\\r?\\n"
        pass

    def t_OTHERS(self, t):
        "."
        pass

    def t_error(self, t):
        pass

    def __init__(self):
        self.lexer = None

    def build(self, **kwargs):
        self.lexer = lex.lex(module=self, **kwargs)

    def test(self, data):
        self.lexer.input(data)
        while True:
             tok = self.lexer.token()
             if not tok:
                 break
             print(tok)

if __name__ == "__main__":
    import sys
    lexer = Lexer()
    lexer.build()
    lexer.test(sys.argv[1])


import time

import gql
from gql.transport.aiohttp import AIOHTTPTransport
from gql.transport.exceptions import TransportError

class MidosHouse:
    def __init__(self):
        self.client = gql.Client(transport=AIOHTTPTransport(url='https://midos.house/api/v1/graphql'))
        self.cache = None
        self.cache_expires_at = time.monotonic()

    async def handles_custom_goal(self, goal_name):
        if time.monotonic() >= self.cache_expires_at:
            try:
                query = gql.gql("""
                    query {
                        goalNames
                    }
                """)
                response = await self.client.execute_async(query)
                self.cache_expires_at = time.monotonic() + 60 * 60 * 24
                self.cache = response['goalNames']
            except TransportError: # if anything goes wrong, assume Mido's House is down and we should handle the room
                self.cache_expires_at = time.monotonic() + 60
                self.cache = None
        if self.cache is None:
            return False
        return goal_name in self.cache


import numpy as np
import cv2 as cv

img = cv.imread("Resources/test.png")
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
cv.imshow("Gray", gray)
lap = cv.Laplacian(gray,cv.CV_64F)
lap = np.uint8(np.absolute(lap))
cv.imshow("Laplacian", lap)

cv.waitKey(0)


#!/usr/bin/env python
import argparse
from termcolor import colored
from app import App
from constants import ERROR_COLOR, KEY_COLOR, INFO_COLOR
from utils import did_you_mean

def run():
    parser = argparse.ArgumentParser(description='Command line key-value store.',
                                     add_help=False, )
    parser.add_argument('action', metavar='action', nargs='*', help='action')
    args = parser.parse_args()
    # command = args or 'help'
    if not args.action:
        command = 'help'
    else:
        command = args.action[0]
    application = App()

    if not hasattr(application, command):
        print (colored('Command `', ERROR_COLOR) +
               colored(command, INFO_COLOR) +
               colored('`not found, Did you mean `', ERROR_COLOR) +
               colored(did_you_mean(command, App.SUPPORTED_COMMANDS), KEY_COLOR) +
               colored('`', ERROR_COLOR))
    else:
        sub_commands = args.action[1:] if args.action else None
        if sub_commands:
            application.call(command, *sub_commands)
        else:
            application.call(command)

if __name__ == "__main__":
    run()


import json
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    age = Column(Integer)
    income = Column(Integer)
    physiological_need = Column(String)
    safety_need = Column(String)
    love_and_belonging_need = Column(String)
    esteem_need = Column(String)
    self_actualization_need = Column(String)

def create_user(db_file: str, age: int, income: int, physiological_need: str, safety_need: str, love_and_belonging_need: str, esteem_need: str, self_actualization_need: str):
    engine = create_engine(f'sqlite:///{db_file}')
    Base.metadata.create_all(engine)

    Session = sessionmaker(bind=engine)
    session = Session()

    new_user = User(age=age,
                    income=income,
                    physiological_need=physiological_need,
                    safety_need=safety_need,
                    love_and_belonging_need=love_and_belonging_need,
                    esteem_need=esteem_need,
                    self_actualization_need=self_actualization_need)

    session.add(new_user)
    session.commit()

    return new_user.id

def update_user(db_file="user.db", user_id="username", age=None, income=None, physiological_need=None, safety_need=None, love_and_belonging_need=None, esteem_need=None, self_actualization_need=None):
    engine = create_engine(f'sqlite:///{db_file}')
    Session = sessionmaker(bind=engine)
    session = Session()

    user = session.query(User).filter_by(id=user_id).first()
    if user is None:
        return "FAILURE"

    if age is not None:
        user.age = age
    if income is not None:
        user.income = income
    if physiological_need is not None:
        user.physiological_need = physiological_need
    if safety_need is not None:
        user.safety_need = safety_need
    if love_and_belonging_need is not None:
        user.love_and_belonging_need = love_and_belonging_need
    if esteem_need is not None:
        user.esteem_need = esteem_need
    if self_actualization_need is not None:
        user.self_actualization_need = self_actualization_need

    session.commit()

    return "SUCCESS"

def get_user(db_file: str, user_id: int):
    engine = create_engine(f'sqlite:///{db_file}')
    Session = sessionmaker(bind=engine)
    session = Session()

    user = session.query(User).filter_by(id=user_id).first()

    # Convert user object to dictionary
    user_dict = {column.name: getattr(user, column.name) for column in user.__table__.columns}

    return user_dict


import json
import logging
import os
import re
import sys
import time

import requests

def get_logger(name):
    log_file = os.getenv('DISKU_LOG_FILE')
    if log_file:
        log_handler = logging.FileHandler(log_file)
    else:
        log_handler = logging.StreamHandler(sys.stdout)

    log_handler.setFormatter(logging.Formatter(
        '%(asctime)s - %(levelname)s - %(name)s - %(message)s',
        '%Y-%m-%d %H:%M:%S %Z'
    ))

    logger = logging.getLogger(name)
    logger.setLevel(os.getenv('DISKU_LOG_LEVEL', 'ERROR'))
    logger.addHandler(log_handler)
    return logger

logger = get_logger(__name__)
logger.debug('DISKU module loaded')

class CaseInsensitiveDict(dict):
    def __repr__(self):
        return 'CaseInsensitiveDict(%r)' % super().__repr__()

    def _find_key(self, key):
        # XXX: iterate over self.keys() is slow
        lkey = key.lower()

        for k in self.keys():
            if k.lower() == lkey:
                return k

        return key

    def __lower_keys__(self):
        # FIXME: handle collisions
        return [k.lower() for k in self.keys()]

    def __contains__(self, key):
        # XXX: performance issue
        return self._find_key(key) in self.__lower_keys__()

    def __getitem__(self, key):
        return super().__getitem__(self._find_key(key))

    def __setitem__(self, key, val):
        return super().__setitem__(self._find_key(key), val)

    def __delitem__(self, key):
        return super().__delitem__(self._find_key(key))

    def get(self, key, defval=None):
        return super().get(self._find_key(key), defval)

class ConfigProxy:
    # TODO: it's read-only, what about set() and __setitem__?
    # consider implement full MutableMapping iter
    def __init__(self, src, namespace):
        # XXX: namespace will become case-insensitive too
        self.src = CaseInsensitiveDict(src)
        self.namespace = namespace

    def key(self, k):
        return '%s.%s' % (self.namespace, k)

    def __contains__(self, key):
        return self.key(k) in self.src

    def __getitem__(self, key):
        return self.src[self.key(key)]

    def get(self, key, defval=None):
        return self.src.get(self.key(key), defval)

def _find_subclass(parent, name):
    name = (name + parent.__name__).lower()

    for klass in parent.__subclasses__():
        if klass.__name__.lower() == name:
            return klass
        raise KeyError('Can not find subclass of %s (name: %s)' % (parent.__name__, name))

class BinaryOperator:
    def __init__(self, op):
        self.op = op
        # FIXME: potential code injection vulnerability
        # should we make a whitelist of allowed operators?
        # *current usage is not vulnerable
        self.f = eval('lambda l, r: l %s r' % op)

    def __call__(self, l, r):
        return self.f(l, r)

    def __repr__(self):
        return 'BinaryOperator(%r)' % self.op

def parse_size_string(s, suffixes='KMGTPEZY'):
    suffix_idx = suffixes.find(s[-1].upper())
    if suffix_idx == -1:
        return int(s)

    return int(s[:-1]) * (1024 ** (suffix_idx + 1))

def parse_time_interval(s):
    suffixes = {
        's': 1,
        'm': 60,
        'h': 60*60,
        'd': 60*60*24,
    }

    try:
        return int(s)
    except ValueError:
        pass

    re_obj = r'(?P<val>[1-9]\d*)(?P<unit>[smhd])'

    if not re.fullmatch('(?:(?:{})+|\s)+'.format(re_obj), s):
        raise ValueError('Invalid time value', s)

    t = 0
    for m in re.finditer(re_obj, s):
        val, unit = m.groups()
        t += int(val) * suffixes[unit]

    return t

class AlertCheck:
    def __init__(self, conditions):
        self.conditions = []
        if not self.parse(conditions):
            raise ValueError('Invalid condition(s): %r' % conditions)

    def parse(self, conditions):
        def parse_val(v):
            if v[-1] == '%':
                return int(v[:-1]) / 100.0
            return parse_size_string(v)

        re_cmp = re.compile(
            r'(?P<var>\w+)'       # variable name
            r'\s*'                # spaces are allowed
            r'(?P<op>[<>]=?|==)'  # compare operator
            r'\s*'                # spaces are allowed
            r'(?P<val>'           # begin value group
            r'100%|0%|[1-9]\d?%|' # percentage
            r'[1-9]\d*[KMGTP]?'   # size
            r')'                  # end value group
            )

        for cond in re.split(r'\s*,\s*', conditions):
            m = re.fullmatch(re_cmp, cond)
            if not m:
                logger.error('Can not parse condition: %s', cond)
                return False

            raw = m.group(0)
            var, op, val = m.groups()
            self.conditions.append((var, BinaryOperator(op), parse_val(val), raw))
            logger.debug('Parsed condition: %s %s %s', var, op, val)

        return True

    @staticmethod
    def validate_params(disk_usage):
        return 'used' in disk_usage and \
               'free' in disk_usage and \
               'total' in disk_usage

    def __call__(self, disk_usage):
        du = CaseInsensitiveDict(disk_usage)
        if not self.validate_params(du):
            raise ValueError('Invalid disk usage status object')
        du['used_p'] = du['used'] / du['total']
        du['free_p'] = du['free'] / du['total']

        for var, op, val, raw in self.conditions:
            if isinstance(val, float):
                var += '_p'

            if op(du.get(var), val):
                return raw

        return False

class AlertChannel:
    '''
    Abstraction class for alert channels
    '''
    _channel_cache = {}

    @classmethod
    def load(cls, config):
        name = config['disku.alert_channel']
        cached = cls._channel_cache.get(name)
        if cached:
            return cached
        try:
            klass = _find_subclass(cls, name)
        except KeyError:
            logger.error('Can not find AlertChannel sublcass: %s', name)
            raise

        instance = klass(ConfigProxy(config, name.lower()))
        instance.prepare()
        return cls._channel_cache.setdefault(name, instance)

    def __init__(self, config):
        self.config = config

    def prepare(self):
        pass

    def fire(self, message):
        raise NotImplemented()

class WebhookAlertChannel(AlertChannel):
    '''
    Webhook alert channel provider, it's made for Slack/Mattermost compatible
    webhook interface
    '''

    def prepare(self):
        try:
            self.mixin = json.loads(self.config.get('mixin', '{}'))
            logger.info('mixin: %r', self.mixin)
        except json.decoder.JSONDecodeError:
            self.mixin = {}

    def fire(self, message):
        data = dict(self.mixin)
        data.update({'text': message})
        logger.debug('webhook sent message: %r', data)

        try:
            resp = requests.post(self.config['url'], json=data)
            logger.debug('response: %r', resp)
            return resp.status_code == 200
        except Exception as e:
            logger.exception('Error during sending http request: %r', e)
            return False

class AlertBuffer:
    def __init__(self, interval, fire):
        self.interval = interval
        self.next_time = 0
        self.buffer = {}
        self.fire = fire

    def push(self, identifier, data):
        self.buffer[identifier] = data

        if time.time() >= self.next_time:
            logger.info('Flushing buffer')
            self.fire(self.buffer)
            self.buffer = {}
            self.next_time = time.time() + self.interval

def test():
    try:
        checker = AlertCheck('FREE == 100G, FREE   <\t 5G, USED     >10G, USED>95%')
        logger.info('Success!')
    except ValueError as e:
        logger.exception('Can not parse condition, error: %r', e)

    for c in checker.conditions:
        logger.info(c)

    GB = 2 ** 30

    logger.info(checker({ 'total': 100 * GB, 'used': 96 * GB, 'free': 4 * GB }))
    logger.info(checker({ 'total': 100 * GB, 'used': 90 * GB, 'free': 10 * GB }))
    logger.info(checker({ 'total': 100 * GB, 'used': 9 * GB, 'free': 91 * GB }))
    logger.info(checker({ 'total': 100 * GB, 'used': 0 * GB, 'free': 100 * GB }))

    for t in '5 10s 10m 2h 1d 24h9d 1s1m1h 1s2m3h4d'.split():
        logger.info('%-10s %d', t, parse_time_interval(t))

if __name__ == '__main__':
    test()


"""
Utilities for testing
"""
from collections import namedtuple

import numpy as np

from .callbacks import ConvergenceCallback
from .cpd import GaussianCPD
from .irt import BayesNetLearner
from .node import Node

EPSILON = 1e-3
NUM_TRIALS = 3

NUM_ITEMS = 50
NUM_INSTR_ITEMS = 0
NUM_LATENT = 1
NUM_CHOICES = 2
NUM_RESPONSES = 500
NUM_STUDENTS = 20
PROB_CORRECT = 0.5

THETA_MU = 0.0
THETA_SIGMA = 1.0

NONOFFSET_COEFF_SHAPE_GEN = 100.0
NONOFFSET_COEFF_SCALE_GEN = 0.01

NONOFFSET_COEFF_SHAPE = 2.0
NONOFFSET_COEFF_SCALE = 0.5

OFFSET_COEFF_MU = 0.0
OFFSET_COEFF_SIGMA = 1.0

INSTR_COEFF_MU = 0.05
INSTR_COEFF_SIGMA = 0.025

THETA_OFFSETS_SIGMA = 0.05

ResponseData = namedtuple('ResponseData', ['correct', 'student_idx', 'item_idx'])

def log_norm_pdf(x, mu=0.0, var=1.0):
    """ Evaluate the log normal pdf.
    :param np.ndarray|float x: point at which to evaluate the log norm pdf
    :param np.ndarray|float mu: mean of the normal distribution
    :param np.ndarray|float var: variance of the normal distribution.
    """
    return -0.5 * np.log(2. * np.pi * var) - 0.5 / var * (x - mu) ** 2

FINITE_DIFF_EPSILON = 1e-6
ALMOST_EQUAL_EPSILON = 1e-4

def finite_diff_grad(x, func, epsilon=FINITE_DIFF_EPSILON):
    """ Approximate the derivative of a function using finite difference.
     :param np.ndarray x: point at which to evaluate derivative
     :param function func: function with which to take finite differences.
     """
    fwd_x = np.copy(x)
    bwd_x = np.copy(x)
    fwd_xx = fwd_x.ravel()
    bwd_xx = bwd_x.ravel()
    y = np.zeros(x.shape)
    yy = y.ravel()
    for i in xrange(x.size):
        fwd_xx[i] += epsilon
        bwd_xx[i] -= epsilon
        yy[i] = (func(fwd_x) - func(bwd_x)) / 2.0 / epsilon
        fwd_xx[i] -= epsilon
        bwd_xx[i] += epsilon
    return y

def finite_diff_hessian(x, grad, epsilon=FINITE_DIFF_EPSILON):
    """ Approximate the Hessian of a function using finite difference in the partial gradient.
    :param np.ndarray x: point at which to evaluate derivative
    :param function grad: function that returns the gradient
    """
    fwd_x = np.copy(x)
    bwd_x = np.copy(x)
    fwd_xx = fwd_x.ravel()
    bwd_xx = bwd_x.ravel()
    y = np.zeros((x.size, x.size))
    for i in xrange(x.size):
        for j in xrange(x.size):
            fwd_xx[i] += epsilon
            bwd_xx[i] -= epsilon
            y[i, j] = (grad(fwd_x).ravel()[j] - grad(bwd_x).ravel()[j]) / 2.0 / epsilon
            fwd_xx[i] -= epsilon
            bwd_xx[i] += epsilon
    return y

def finite_diff_hessian_diag(x, grad, epsilon=FINITE_DIFF_EPSILON):
    """ Approximate the diagonal of the Hessian of a function using finite difference in the
    partial gradient.
    :param np.ndarray x: point at which to evaluate derivative
    :param function grad: function that returns the gradient
    """
    fwd_x = np.copy(x)
    bwd_x = np.copy(x)
    fwd_xx = fwd_x.ravel()
    bwd_xx = bwd_x.ravel()
    y = np.zeros(x.shape)
    yy = y.ravel()
    for i in xrange(x.size):
        fwd_xx[i] += epsilon
        bwd_xx[i] -= epsilon
        yy[i] = (grad(fwd_x).ravel()[i] - grad(bwd_x).ravel()[i]) / 2.0 / epsilon
        fwd_xx[i] -= epsilon
        bwd_xx[i] += epsilon
    return y

def generate_data(num_students=NUM_STUDENTS,
                  num_items=NUM_ITEMS,
                  num_responses=NUM_RESPONSES,
                  prob_correct=PROB_CORRECT):
    """ Simulate student response data (independently of any parameters).

    :param int num_students: Number of unique student ids.
    :param int num_items: number of assessment items
    :param int num_responses: number of responses to generate
    :param float prob_correct: probability of correct (probability of choosing first choice when
                               num_choices > 1; probability of other choices are all equal)
    :return: the response data
    :rtype: ResponseData
    """
    correct = np.random.rand(num_responses) < prob_correct
    num_responses_per_student, remainder = divmod(num_responses, num_students)
    unique_student_ids = range(num_students)
    student_idx = [reg_id for reg_id in unique_student_ids for _ in
                   range(num_responses_per_student)]
    # If num_responses can't be perfectly divided into students, add the remaining responses
    # to the last student id:
    student_idx.extend([unique_student_ids[-1]] * remainder)
    student_idx = np.array(student_idx)

    item_idx = np.random.random_integers(low=0, high=num_items-1, size=num_responses)
    np.random.shuffle(student_idx)

    return ResponseData(correct, student_idx, item_idx)

class MockNode(Node):
    """
    A test node class that stores the evidence terms passed into it and does nothing with them,
    and whose update method returns a dictionary with param node names
    """

    def __init__(self, *args, **kwargs):
        super(MockNode, self).__init__(*args, **kwargs)
        self.obtained_evidence_terms = {}

    def update(self, evidence_terms=None):
        """ An update function that stores all the evidence infos passed to it, and sets its
        log_prob to a random Gaussian value

        :param list evidence_terms: evidence information passed into the node
        :return: the names of all param nodes
        :rtype: dict[Node, str]
        """
        if evidence_terms is not None:
            self.obtained_evidence_terms.update(evidence_terms)
        self.log_prob = np.random.randn()
        return {v: v.name for k, v in self.param_nodes.iteritems()}

class MockLearner(BayesNetLearner):
    """
    A learner with the following graph of TestNodes (directed edges pointing down):

       A
       |
       B
      / \
     C  D
     \ / \
     E   F
    """

    def __init__(self):
        cpd = GaussianCPD(dim=1)
        node_a = MockNode(name='A', data=None, cpd=cpd)
        node_b = MockNode(name='B', data=None, cpd=cpd, param_nodes={'mean': node_a})
        node_c = MockNode(name='C', data=None, cpd=cpd, param_nodes={'mean': node_b})
        node_d = MockNode(name='D', data=None, cpd=cpd, param_nodes={'mean': node_b})
        node_e = MockNode(name='E', data=None, cpd=cpd, param_nodes={'mean': node_c,
                                                                     'precision': node_d})
        node_f = MockNode(name='F', data=None, cpd=cpd, param_nodes={'mean': node_d})
        super(MockLearner, self).__init__(nodes=[node_a, node_b, node_c, node_d, node_e, node_f],
                                          max_iterations=1, callback=ConvergenceCallback())


import torch
import torch.nn as nn
import torch.nn.functional as F
from transformers import *
from transformers.modeling_roberta import RobertaLMHead
from transformers.modeling_bert import BertOnlyMLMHead

class BertMLM(BertPreTrainedModel):
    """BERT model with the masked language modeling head.
    """
    def __init__(self, config):
        super(BertMLM, self).__init__(config)
        self.bert = BertModel(config)
        self.cls = BertOnlyMLMHead(config)
        self.init_weights()
        self.tie_weights()

    def get_trainable_parameters(self):
        # this is useful when freezing the encoder parameters
        return list(self.bert.embeddings.word_embeddings.parameters()) + [self.cls.predictions.bias]

    def tie_weights(self):
        self.cls.predictions.decoder.weight = self.bert.embeddings.word_embeddings.weight

    def forward(self, input_ids, token_type_ids=None, attention_mask=None, masked_lm_labels=None):
        outputs = self.bert(input_ids, token_type_ids, attention_mask)
        sequence_output = outputs[0]
        pred_mask = masked_lm_labels.ne(-1)
        pred_vect = sequence_output[pred_mask]  # (bs, slen, dim)
        y = torch.masked_select(masked_lm_labels, pred_mask)
        prediction_scores = self.cls(pred_vect)
        masked_lm_loss = F.cross_entropy(prediction_scores, y)
        return masked_lm_loss

class RobertaMLM(BertPreTrainedModel):
    """RoBERTa model with the masked language modeling head.
    """
    def __init__(self, config):
        super(RobertaMLM, self).__init__(config)
        self.roberta = RobertaModel(config)
        self.lm_head = RobertaLMHead(config)
        self.init_weights()
        self.tie_weights()

    def get_trainable_parameters(self):
        return list(self.roberta.embeddings.word_embeddings.parameters()) + [self.lm_head.bias]

    def tie_weights(self):
        self.lm_head.decoder.weight = self.roberta.embeddings.word_embeddings.weight

    def forward(self, input_ids, token_type_ids=None, attention_mask=None, masked_lm_labels=None):
        outputs = self.roberta(input_ids, token_type_ids, attention_mask)
        sequence_output = outputs[0]
        pred_mask = masked_lm_labels.ne(-1)
        pred_vect = sequence_output[pred_mask]  # (bs, slen, dim)
        y = torch.masked_select(masked_lm_labels, pred_mask)
        prediction_scores = self.lm_head(pred_vect)
        masked_lm_loss = F.cross_entropy(prediction_scores, y)
        return masked_lm_loss

class BertAdaptor(nn.Module):
    """
    A class for adapting English BERT to other languages
    """
    def __init__(self, src_model, tgt_model):
        """
        src_model: (BertForMaskedLM) of English
        tgt_model: (BertForMaskedLM) of Foreign
        """
        super(BertAdaptor, self).__init__()
        self.src_model = src_model
        self.tgt_model = tgt_model

        # force sharing params
        self.tgt_model.bert.encoder = self.src_model.bert.encoder
        self.tgt_model.bert.pooler = self.src_model.bert.pooler
        # share embedding params
        self.tgt_model.bert.embeddings.position_embeddings = self.src_model.bert.embeddings.position_embeddings
        self.tgt_model.bert.embeddings.token_type_embeddings = self.src_model.bert.embeddings.token_type_embeddings
        self.tgt_model.bert.embeddings.LayerNorm = self.src_model.bert.embeddings.LayerNorm
        # share output layers
        self.tgt_model.cls.predictions.transform = self.src_model.cls.predictions.transform

    def forward(self, lang, input_ids, token_type_ids=None,
                attention_mask=None, masked_lm_labels=None):
        model = self.src_model if lang == 'en' else self.tgt_model
        return model(input_ids, token_type_ids, attention_mask=attention_mask,
                     masked_lm_labels=masked_lm_labels)

class RobertaAdaptor(nn.Module):
    """
    A class for adapting English BERT to other languages
    """
    def __init__(self, src_model, tgt_model):
        """
        src_model: (BertForMaskedLM) of English
        tgt_model: (Roberta) of Foreign
        """
        super(RobertaAdaptor, self).__init__()
        self.src_model = src_model
        self.tgt_model = tgt_model

        # force sharing params
        self.tgt_model.roberta.encoder = self.src_model.roberta.encoder
        self.tgt_model.roberta.pooler = self.src_model.roberta.pooler
        # share embedding params
        self.tgt_model.roberta.embeddings.position_embeddings = self.src_model.roberta.embeddings.position_embeddings
        self.tgt_model.roberta.embeddings.token_type_embeddings = self.src_model.roberta.embeddings.token_type_embeddings
        self.tgt_model.roberta.embeddings.LayerNorm = self.src_model.roberta.embeddings.LayerNorm
        # share output layers
        self.tgt_model.lm_head.dense = self.src_model.lm_head.dense
        self.tgt_model.lm_head.layer_norm = self.src_model.lm_head.layer_norm

    def forward(self, lang, input_ids, token_type_ids=None,
                attention_mask=None, masked_lm_labels=None):
        model = self.src_model if lang == 'en' else self.tgt_model
        return model(input_ids, token_type_ids, attention_mask=attention_mask,
                     masked_lm_labels=masked_lm_labels)


from __future__ import annotations
import dataclasses
import enum

import grpc
from tensorflow_serving.apis.model_pb2 import ModelSpec
from tensorflow_serving.apis.model_service_pb2_grpc import ModelServiceStub
from tensorflow_serving.apis.prediction_service_pb2_grpc import PredictionServiceStub
from tensorflow_serving.apis.model_management_pb2 import ReloadConfigRequest
from tensorflow_serving.apis.get_model_status_pb2 import GetModelStatusRequest
from tensorflow_serving.apis.predict_pb2 import PredictRequest
from tensorflow_serving.apis.get_model_metadata_pb2 import (
    GetModelMetadataRequest,
    SignatureDefMap,
)
from tensorflow_serving.config.model_server_config_pb2 import (
    ModelServerConfig,
    ModelConfigList,
    ModelConfig,
)
from tensorflow.core.framework.types_pb2 import DataType
from tensorflow.core.protobuf.meta_graph_pb2 import TensorInfo
from tensorflow.core.framework.tensor_pb2 import TensorProto
from tensorflow.core.framework.tensor_shape_pb2 import TensorShapeProto

class ModelStatus(enum.Enum):
    # Default value.
    UNKNOWN = 0
    # The manager is tracking this servable, but has not initiated any action
    # pertaining to it.
    START = 10
    # The manager has decided to load this servable. In particular, checks
    # around resource availability and other aspects have passed, and the
    # manager is about to invoke the loader's Load() method.
    LOADING = 20
    # The manager has successfully loaded this servable and made it available
    # for serving (i.e. GetServableHandle(id) will succeed). To avoid races,
    # this state is not reported until *after* the servable is made
    # available.
    AVAILABLE = 30
    # The manager has decided to make this servable unavailable, and unload # it. To avoid races, this state is reported *before* the servable is
    # made unavailable.
    UNLOADING = 40
    # This servable has reached the end of its journey in the manager. Either
    # it loaded and ultimately unloaded successfully, or it hit an error at
    # some point in its lifecycle.
    END = 50

@dataclasses.dataclass
class TensorMeta:
    name: str
    dtype: DataType
    shape: list[int]

class TFServing:
    def __init__(
        self,
        grpc_channel: grpc.Channel,
        base_path: str,
        timeout: int = 5,
        reloading_timeout: int | None = None,
    ) -> None:
        self.base_path = base_path
        self.timeout = timeout
        self.reloading_timeout = reloading_timeout or self.timeout
        self.model_service_stub = ModelServiceStub(grpc_channel)
        self.prediction_service_stub = PredictionServiceStub(grpc_channel)

    def reload_config(self, model_names: list[str]) -> None:
        model_configs: list[ModelConfig] = []
        for model_name in model_names:
            model_configs.append(
                ModelConfig(
                    name=model_name,
                    base_path="/".join([self.base_path, model_name]),
                    model_platform="tensorflow",
                )
            )
        model_config_list = ModelConfigList(config=model_configs)
        request = ReloadConfigRequest(
            config=ModelServerConfig(model_config_list=model_config_list)
        )
        self.model_service_stub.HandleReloadConfigRequest(
            request, timeout=self.reloading_timeout
        )

    def get_model_metadata(
        self,
        model_name: str,
        input_names: list[str] | None = None,
        output_names: list[str] | None = None,
    ) -> tuple[list[TensorMeta], list[TensorMeta]]:
        model_spec = ModelSpec(name=model_name, signature_name="serving_default")
        request = GetModelMetadataRequest(
            model_spec=model_spec, metadata_field=["signature_def"]
        )
        response = self.prediction_service_stub.GetModelMetadata(
            request, timeout=self.timeout
        )
        def_map = SignatureDefMap()
        response.metadata["signature_def"].Unpack(def_map)
        metadata = def_map.signature_def["serving_default"]

        if input_names is None:
            input_names = list(metadata.inputs.keys())
        if output_names is None:
            output_names = list(metadata.outputs.keys())

        def read_tensor_meta(
            names: list[str], tensor_info: dict[str, TensorInfo]
        ) -> list[TensorMeta]:
            tensor_metas: list[TensorMeta] = []
            for name in names:
                tensor = tensor_info[name]
                dims = [d.size for d in tensor.tensor_shape.dim]
                tensor_meta = TensorMeta(name, tensor.dtype, dims)
                tensor_metas.append(tensor_meta)
            return tensor_metas

        return (
            read_tensor_meta(input_names, metadata.inputs),
            read_tensor_meta(output_names, metadata.outputs),
        )

    def get_model_status(self, model_name: str) -> ModelStatus:
        model_spec = ModelSpec(name=model_name)
        request = GetModelStatusRequest(model_spec=model_spec)
        response = self.model_service_stub.GetModelStatus(request, timeout=self.timeout)
        for version_status in response.model_version_status:
            if version_status.version == 0:
                return ModelStatus(version_status.state)
        return ModelStatus(0)

    def predict(
        self, model_name: str, input_tensor: dict[str, TensorProto]
    ) -> dict[str, TensorProto]:
        model_spec = ModelSpec(name=model_name)
        request = PredictRequest(model_spec=model_spec)
        for name, tensor in input_tensor.items():
            request.inputs[name].CopyFrom(tensor)
        return dict(
            self.prediction_service_stub.Predict(request, timeout=self.timeout).outputs
        )

if __name__ == "__main__":
    s = TFServing(grpc.insecure_channel("127.0.0.1:8500"))
    s.reload_config(["xxx", "xyz"])
    print(s.get_model_metadata("xxx"))
    tensor = TensorProto(
        dtype=DataType.DT_INT64,
        tensor_shape=TensorShapeProto(
            dim=[TensorShapeProto.Dim(size=1), TensorShapeProto.Dim(size=5)]
        ),
        int64_val=[230, 2130, 4324, 222, 0],
    )
    print(s.predict("xxx", {"token_ids": tensor}))


from itertools import dropwhile

from io_utils import read_file, write_file

def clear_missed_rides(rides, max_time, ctime):
    time_left = max_time - ctime
    if rides and rides[0].score > time_left:
        rides = list(dropwhile(lambda x: x.score > time_left, rides))
    return rides

def run_example(input_file, output_file):
    print("Reading file: {}\n".format(input_file))
    max_time, bonus, cars, rides, cars_nb = read_file(input_file)
    for ctime in range(max_time):
        cars_idle = 0
        for car in cars:
            car.drive(rides)
            if car.current_ride is None:
                cars_idle += 1
        rides = clear_missed_rides(rides, max_time, ctime)
        if not rides and cars_idle == cars_nb:
            break
    write_file(cars, output_file)


from selenium import webdriver
import time
from selenium.common.exceptions import NoSuchElementException
import random

class amdAutomation():

    def __init__(self):
        self.driver = None

    def setWebsiteLocation(self, link):
        self.driver = webdriver.Chrome('/Users/chiraag/chromedriver')
        self.driver.get(link)

    def executeTest(self, link):
        self.setWebsiteLocation(link)
        self.addToCart()

    def addToCart(self):
        i = 1
        while i == 1:
            try:
                print("trying this")
                addToCart_btn = self.driver.find_element_by_xpath("//button[contains(text(),'Add to Cart')]");
                addToCart_btn.click()
                i = 2
            except NoSuchElementException:
                print("sleeping now for " + str(3) + " seconds")
                time.sleep(3)
                self.driver.refresh()
                i = 1
        print("adding to cart :)")

if __name__ == "__main__":
    taskmaster = amdAutomation()
    taskmaster.executeTest('https://www.amd.com/en/direct-buy/5458372200/us')

#search = browser.find_element_by_name('st')
#search.send_keys("rtx 3080")

#search_btn = browser.find_element_by_xpath("/html/body/div[3]/main/div[2]/div/div[1]/div[3]/div[2]/div/div[2]/div[1]/div/div/div[1]")
#search_btn.click()

'''

'''


from time import perf_counter_ns # Calcul temps d'exécution
import matplotlib.pyplot as plt # Graphes

def InsertSort(l):
    """
    entree :
    --------
    l : liste d’entier ou réel
            liste à trier

    Sortie :
    --------
    l : liste triée
            Attention la liste initiale est modifiée.
    """
    n = len(l)
    for i in range(n):
        x = l[i]
        j = i
        while j > 0 and l[j-1] > x:
            l[j] = l[j-1]
            j-=1
        l[j] = x

if __name__=='__main__': # test
    listTimeIS = [[],[]]
    listTimesort = [[],[]]
    rlist = [5,500,2000,5000,10000,15000,20000]
    """
    # InsertionSort()
    for r in rlist: # + favorable
        l = list(range(r))
        start = perf_counter_ns()
        sl = InsertSort(l)
        end = perf_counter_ns()
        execution_time = round((end - start)*10**(-6),3)
        listTimeIS[0].append(execution_time)
        print("Time passed :",listTimeIS[0][rlist.index(r)])

    for r in rlist: # - favorable
        l = list(range(r))
        l.reverse()
        start = perf_counter_ns()
        sl = InsertSort(l)
        end = perf_counter_ns()
        execution_time = round((end - start)*10**(-6),3)
        listTimeIS[1].append(execution_time)
        print("Time passed :",listTimeIS[1][rlist.index(r)])

    # méthode sort()
    for r in rlist: # + favorable
        l = list(range(r))
        start = perf_counter_ns()
        l.sort()
        end = perf_counter_ns()
        execution_time = round((end - start)*10**(-6),3)
        listTimesort[0].append(execution_time)
        print("Time passed :",listTimesort[0][rlist.index(r)])

    for r in rlist: # - favorable
        l = list(range(r))
        l.reverse()
        start = perf_counter_ns()
        l.sort()
        end = perf_counter_ns()
        execution_time = round((end - start)*10**(-6),3)
        listTimesort[1].append(execution_time)
        print("Time passed :",listTimesort[1][rlist.index(r)])

    print("+ favorable InsertSort() (en ms) :",listTimeIS[0])
    print("- favorable InsertSort() (en ms) :",listTimeIS[1])
    print("+ favorable sort() (en ms) :",listTimesort[0])
    print("- favorable sort() (en ms) :",listTimesort[1])
    """
    listTimeIS[0] = [0.003, 0.218, 0.783, 1.861, 2.92, 5.759, 10.202]
    listTimeIS[1] = [0.012, 64.902, 642.989, 2818.485, 10652.621, 24741.013, 48911.853]
    listTimesort[0] = [0.004, 0.008, 0.151, 0.058, 0.146, 0.231, 0.172]
    listTimesort[1] = [0.002, 0.004, 0.058, 0.058, 0.155, 0.459, 0.333]

    plt.title("Comparaison InsertSort() et sorted()")
    # InsertSort()
    plt.plot(rlist,listTimeIS[0],"ro-",label="InsertSort() favorable (triée)")
    plt.plot(rlist,listTimeIS[1],"o-",label="InsertSort() défavorable (reversed)")
    # Methode sort()
    plt.plot(rlist,listTimesort[0],"go-",label="sorted() favorable (triée)")
    plt.plot(rlist,listTimesort[1],"bo-",label="sorted() défavorable (reversed)")

    plt.legend()
    plt.ylabel("Temps d'exécution (en ms)")
    plt.xlabel("Nombre d'éléments (n)")
    plt.show()


from flask import render_template, Blueprint
from app.model import Article, User, Category, Tag

blueprint = Blueprint('front', __name__, template_folder='templates')

@blueprint.route("/")
def index():
    result = Article.query.getall()
    categorys = Category.query.all()
    #tags = Tag.query.all()

    temp = Article.query.all()
    tags = list()
    dict = {}
    for t in temp:
        for tag in t.tag:
            count = dict.get(tag.name)
            if dict.get(tag.name):
                dict.update({
                    tag.name: count + 1
                })
            else:
                dict.update({
                    tag.name: 1
                })

    return render_template("index.html", articles=result, categorys=categorys, tags=dict)

@blueprint.route('/article/<int:pageid>')
def article(pageid=1):
    result = Article.query.getart(pageid)
    return render_template("article.html", article=result)

@blueprint.route('/contact/')
def contact():
    return render_template("contact.html")


import pygame

class Sprite(pygame.sprite.Sprite):
    def __init__(self, groups=[]):
        super().__init__(groups)

        # The state for the sprite
        self.state = "released"
        self.mouse_state = "released"

        # This makes sure that the rect actually exists
        # self.rect = self.rect

    def refresh(self):
        print("NOT IMPLEMENTED!!! (refresh) (for " + self.__class__.__name__ + ")")

    def refresh_sprite(self, action, mouse_pos):
        self.refresh()
        return_value = None
        if action == "press":
            self.mouse_state = "pressed"
        elif action == "release":
            self.mouse_state = "released"
        if self.screen_rect.collidepoint(mouse_pos):
            if action == "release":
                return_value = self.click()
            elif self.mouse_state == "pressed":
                self.state = "pushed"
                return_value = self.push()
            else:
                self.state = "highlighted"
                return_value = self.highlight()
        else:
            self.state = "released"
            return_value = self.release()

        # print(self.mouse_state)
        return return_value

    def push(self):
        print("NOT IMPLEMENTED!!! (release) (for " + self.__class__.__name__ + ")")
        return None

    def highlight(self):
        print("NOT IMPLEMENTED!!! (release) (for " + self.__class__.__name__ + ")")
        return None

    def release(self):
        print("NOT IMPLEMENTED!!! (release) (for " + self.__class__.__name__ + ")")
        return None

    def click(self):
        print("NOT IMPLEMENTED!!! (click) (for " + self.__class__.__name__ + ")")
        return None


#
# @lc app=leetcode.cn id=122 lang=python3
#
# [122] 买卖股票的最佳时机 II
#
from typing import List
# @lc code=start
class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        #---------------------------------------------------------------#
        #    贪心算法
        #    计算相隔两天的利润
        #    利润为正就sum++
        #    利润不加或减就忽略
        #---------------------------------------------------------------#
        sum = 0 # 钱数
        l = len(prices) # 交易天数
        for i in range(l-1):
            if prices[i+1] > prices[i]:
                sum += prices[i+1] - prices[i]
        return sum

# @lc code=end

贪心算法/122.买卖股票的最佳时机-ii.py