"""Prepares the backend data and APIs to be displayed on the frontend. """
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import redirect
from django.template import loader
from datetime import datetime
import requests
from django.db.models import Count, Sum
from home.models import Ingredient, Item, ItemsIngredient, Augmentation, Order, OrdersItem, OrdersItemsAugmentation
from django.shortcuts import render
from threading import Thread

# weather API
forecast = requests.get("https://api.weather.gov/gridpoints/HGX/29,134/forecast").json()['properties']['periods'][0]
#return HttpResponse(template.render({'forecast': forecast}, request))

#
def index(request):
    """home page, diverges into cashier / manager."""
    template = loader.get_template("home/index.html")
    context = {'forecast': forecast}
    return HttpResponse(template.render(context, request))

# login redirect, diverges into cashier / manager
def login(request):
    request.session['logged_in'] = True
    request.session.modified = True
    return redirect("/employee/")

#
def logout(request):
    request.session['logged_in'] = False
    request.session.modified = True
    return redirect('/accounts/logout/')

#
def employee(request):
    if redirect_logged_out(request):
        return redirect_logged_out(request)
    template = loader.get_template("home/employee.html")
    context = {'forecast': forecast}
    return HttpResponse(template.render(context, request))

#
def cashier_index(request):
    """home page of cashier - includes menu items."""
    if redirect_logged_out(request):
        return redirect_logged_out(request)
    if request.method == 'POST':

        #delete button functionality
        if request.POST.get("delete"):
            item_to_delete_id = request.POST.get("delete")
            updated_order_items = []
            deleted = False

            for item in request.session.get('order_items', []):
                if item.split(',')[0] == item_to_delete_id and not deleted:
                    deleted = True
                    continue
                updated_order_items.append(item)

            request.session['order_items'] = updated_order_items
            total_price = 0
            for item in request.session['order_items']:
                item_id = item.split(',')[0]
                total_price += Item.objects.get(item_id=item_id).price
                for augmentation in request.session.get('order_item_augs', []):
                    if augmentation[0] == item:
                        total_price += Augmentation.objects.get(augmentation_id=augmentation[1]).price

            request.session['total_price'] = total_price
            request.session.modified = True

            item_ids_in_session = [item.split(',')[0] for item in request.session['order_items']]
            items = Item.objects.filter(item_id__in=item_ids_in_session).order_by('category')
            context = {
                'forecast': forecast,
                'items': items,
                'total_price': total_price
            }

            template = loader.get_template("home/cashier/edit_cart.html")
            return HttpResponse(template.render(context, request))

        elif request.POST.get("place_order"):
            #checking to see if there are enough ingredients to place an order
            total_ingredients_required = {}

            for item in request.session.get('order_items', []):
                itemid = item.split(',')[0]
                for item_ingredient in ItemsIngredient.objects.filter(item_id=itemid):
                    total_ingredients_required[item_ingredient.ingredient_id] = (
                        total_ingredients_required.get(item_ingredient.ingredient_id, 0)
                        + item_ingredient.amount
                    )

                ignore_augmentation_ids = [20, 21, 22, 23, 24] # Ice
                for augmentation in request.session.get('order_item_augs', []):
                    if augmentation[0] == item and augmentation[1] not in ignore_augmentation_ids:
                        augmentation_obj = Augmentation.objects.get(augmentation_id=augmentation[1])
                        total_ingredients_required[augmentation_obj.ingredient_id] = (
                            total_ingredients_required.get(augmentation_obj.ingredient_id, 0)
                            + augmentation_obj.amount
                        )
            item_ids_in_session = [item.split(',')[0] for item in request.session['order_items']]
            items = Item.objects.filter(item_id__in=item_ids_in_session).order_by('category')
            for ingredient_id, required_amount in total_ingredients_required.items():
                ingredient = Ingredient.objects.get(ingredient_id=ingredient_id)
                if ingredient.amount < required_amount:
                    total_price=0
                    context = {
                        'forecast': forecast,
                        'items': items,
                        'total_price': total_price,
                        'message': 'Cannot place order due to insufficient ingredients.',
                    }
                    template = loader.get_template("home/cashier/edit_cart.html")
                    return HttpResponse(template.render(context, request))
            thread = Thread(target = place_order, args = (request, True, ))
            thread.start()
        elif request.POST.get('category'):
            request.session['category'] = request.POST.get('category')
        else:
            ice_level = int(request.POST.get('ice'))
            sweetness_level = int(request.POST.get('sweetness'))
            milk_level = int(request.POST.get('milk'))
            milk_type = int(request.POST.get('milktype'))
            toppings = [int(i) for i in request.POST.getlist('toppings')]
            augmentations = [ice_level, sweetness_level, milk_type * 5 + milk_level, *tuple(toppings)]
            if 'order_items' not in request.session:
                request.session['order_items'] = []
            item_id = f"{request.session['item_id']},{len(request.session['order_items'])}"
            request.session['order_items'].append(item_id)
            if 'order_item_augs' not in request.session:
                request.session['order_item_augs'] = []
            if 'total_price' not in request.session:
                request.session['total_price'] = 0
            request.session['total_price'] += Item.objects.get(item_id=request.session['item_id']).price
            for aug in augmentations:
                request.session['total_price'] += Augmentation.objects.get(augmentation_id=aug).price
            for augmentation_id in augmentations:
                request.session['order_item_augs'].append((item_id, augmentation_id))
    else:
        request.session.flush()
        request.session['logged_in'] = True
        request.session['category'] = Item.objects.order_by('category').values('category').annotate(dcount=Count('category'))[0]['category']

    request.session.modified = True
    template = loader.get_template("home/cashier/index.html")

    if 'category' not in request.session:
         request.session['category'] = Item.objects.order_by('category').values('category').annotate(dcount=Count('category'))[0]['category']
    categories = [category['category'] for category in Item.objects.order_by('category').values('category').annotate(dcount=Count('category'))]
    items = Item.objects.order_by('name').filter(category=request.session['category'])
    context = {
        'forecast': forecast,
        'items': items,
        'categories':  categories,
    }
    return HttpResponse(template.render(context, request))

#
def cashier_edit_cart(request):
    """Option to remove items from an order."""
    template = loader.get_template("home/cashier/edit_cart.html")
    items = []
    if 'order_items' in request.session:
        items = [Item.objects.get(item_id=i.split(',')[0]) for i in request.session['order_items']]
    total_price = request.session.get('total_price', 0)
    context = {
        'forecast': forecast,
        'items': items,
        'total_price': total_price
    }
    return HttpResponse(template.render(context, request))

# Add ice level, sugar, milk, and extra to tea.
def cashier_tea_specifications(request):
    """Add ice level, sugar, milk, and extra to tea."""
    if request.method == "POST":
        item = request.POST.get('item', None)

    template = loader.get_template("home/cashier/tea_specifications.html")

    if item != None:
        item = Item.objects.get(item_id=item)

    request.session['item_id'] = item.item_id

    request.session.modified = True

    context = {
        'forecast': forecast,
        'item': item
    }
    return HttpResponse(template.render(context, request))

#
def customer_edit_cart(request):
    """Option to remove items from an order."""
    template = loader.get_template("home/customer/edit_cart.html")
    items = []
    if 'order_items' in request.session:
        items = [Item.objects.get(item_id=i.split(',')[0]) for i in request.session['order_items']]
    total_price = request.session.get('total_price', 0)
    context = {
        'forecast': forecast,
        'items': items,
        'total_price': total_price
    }
    return HttpResponse(template.render(context, request))

# Add ice level, sugar, milk, and extra to tea.
def customer_tea_specifications(request):
    """Add ice level, sugar, milk, and extra to tea."""
    if request.method == "POST":
        item = request.POST.get('item', None)

    template = loader.get_template("home/customer/tea_specifications.html")

    if item != None:
        item = Item.objects.get(item_id=item)

    request.session['item_id'] = item.item_id

    request.session.modified = True

    context = {
        'forecast': forecast,
        'item': item
    }
    return HttpResponse(template.render(context, request))

# View inventory and click an ingredient to view it's fill level.
def manager_inventory(request):
    if redirect_logged_out(request):
        return redirect_logged_out(request)
    template = loader.get_template("home/manager/inventory.html")
    ingredients = Ingredient.objects.order_by('name').all()
    context = {
        'forecast': forecast,
        'ingredients': ingredients
    }
    return HttpResponse(template.render(context, request))

#
def manager_restock_report(request):
    """View inventory items whose stock is below 20% of fill level"""
    if redirect_logged_out(request):
        return redirect_logged_out(request)
    template = loader.get_template("home/manager/restock_report.html")
    ingredient_rows = Ingredient.objects.order_by('name').all()
    ingredients = [ingredient for ingredient in ingredient_rows if ingredient.amount / ingredient.fill_level < 0.2]
    context = {
        'forecast': forecast,
        'ingredients': ingredients
    }
    return HttpResponse(template.render(context, request))

#
def manager_item_fill_level(request):
    """Set fill level and restockk ingredient."""
    if redirect_logged_out(request):
        return redirect_logged_out(request)
    if request.method == "POST":
        # Handle the form submission
        id = request.POST.get("ingredient")
        new_fill_level = request.POST.get("new_fill_level")
        restock = request.POST.get("restock")

    template = loader.get_template("home/manager/item_fill_level.html")

    # Handle Item Click / Reload Page (using session)
    if (id == None):
        id = request.session['ingredient']
    else:
        request.session['ingredient'] = id

    ingredient = Ingredient.objects.get(ingredient_id = id)

    # Handle 'Set Fill Level'
    if new_fill_level:
        ingredient.fill_level = float(new_fill_level)
    else:
        new_fill_level = ingredient.fill_level

    # Handle 'Restock to Fill Level'
    if restock:
        ingredient.amount = ingredient.fill_level

    ingredient.save()
    request.session.modified = True

    context = {
        'forecast': forecast,
        'ingredient': ingredient,
        'new_fill_level': new_fill_level,
    }
    return HttpResponse(template.render(context, request))

#
def manager_index(request):
    """Home page for manager."""
    if redirect_logged_out(request):
        return redirect_logged_out(request)
    template = loader.get_template("home/manager/index.html")
    return HttpResponse(template.render({}, request))

#
def manager_order_history(request):
    """View past orders."""
    if redirect_logged_out(request):
        return redirect_logged_out(request)
    template = loader.get_template("home/manager/order_history.html")

    orders = Order.objects.order_by('-order_id').all()
    orders = orders[:25]
    prices = []
    items_strings = []
    for order in orders:
        items = OrdersItem.objects.filter(order_id=order.order_id)
        item_string = ""
        total_price = 0.0
        for obj in items:
            item_string += obj.item.name + ", "
            # ordersAug = OrdersItemsAugmentation.objects.filter(order_id=order.order_id,item_id=obj.item.item_id)
            total_price += obj.item.price

        item_string = item_string[:-2] #removes last ", "
        items_strings.append(item_string)
        prices.append(total_price)

        # items += OrdersItem.objects.filter(order_id=orders[i].order_id)

    # employees = []
    # for order in orders:
    #         employees.append(Employee.objects.get(employee_id=order.employee.employeeID).name)

    data = zip(orders, items_strings, prices)

    context = {
        'data':data,
    }
    return HttpResponse(template.render(context, request))

def manager_excess_report(request):
    if redirect_logged_out(request):
        return redirect_logged_out(request)
    if request.method == 'POST':
        start_time = request.POST.get('start_time')
        end_time = request.POST.get('end_time')

        start_datetime = datetime.strptime(start_time, '%Y-%m-%dT%H:%M')
        end_datetime = datetime.strptime(end_time, '%Y-%m-%dT%H:%M')

        orders = Order.objects.filter(time__range=(start_datetime, end_datetime))

        all_ingredients_dict = {ingredient.ingredient_id: ingredient for ingredient in Ingredient.objects.all()}

        ingredient_usage = {ingredient_id: 0 for ingredient_id in all_ingredients_dict}
        if orders.exists():
            item_ingredients_usage = ItemsIngredient.objects.filter(
                item__ordersitem__order__in=orders
            ).values('ingredient_id').annotate(total_amount=Sum('amount'))

            augmentation_ingredients_usage = OrdersItemsAugmentation.objects.filter(
                pair__order__in=orders,
                augmentation__ingredient_id__isnull=False
            ).values('augmentation__ingredient_id').annotate(total_amount=Sum('augmentation__amount'))

            for usage in item_ingredients_usage:
                ingredient_id = usage['ingredient_id']
                ingredient_usage[ingredient_id] += usage['total_amount']

            for usage in augmentation_ingredients_usage:
                ingredient_id = usage['augmentation__ingredient_id']
                ingredient_usage[ingredient_id] += usage['total_amount']

            excess_inventory = [
                all_ingredients_dict[ingredient_id].name
                for ingredient_id, used_amount in ingredient_usage.items()
                if used_amount < 0.1 * (all_ingredients_dict[ingredient_id].amount+used_amount)
            ]
        else:
            #If no orders exist all ingredients are considered excess
            excess_inventory = list(Ingredient.objects.values_list('name', flat=True))

        context = {
            'excess_inventory': excess_inventory
        }
        return render(request, 'home/manager/excess_report.html', context)
    else:
        return render(request, 'home/manager/excess_report.html')

# View order trends.
def manager_order_trends(request):
    """View order trends."""
    if redirect_logged_out(request):
        return redirect_logged_out(request)
    if request.method == "POST":
        item = request.POST.get("item")
        start = datetime.strptime(request.POST.get("start"), "%Y-%m-%dT%H:%M")
        end = datetime.strptime(request.POST.get("end"), "%Y-%m-%dT%H:%M")
        interval = (end - start) / 15
        current = start
        sales_data = {}
        while current < end:
            item_sales = OrdersItem.objects.filter(order__time__gte=current, order__time__lte=(current+interval), item__name=item).aggregate(Sum("item__price"))
            augmentation_sales = OrdersItemsAugmentation.objects.filter(pair__order__time__gte=current, pair__order__time__lte=(current+interval), pair__item__name=item).aggregate(Sum("augmentation__price"))
            sales_data[current] = 0
            if item_sales:
                sales_data[current] += item_sales["item__price__sum"] if item_sales["item__price__sum"] else 0
            if augmentation_sales:
                sales_data[current] += augmentation_sales["augmentation__price__sum"] if augmentation_sales["augmentation__price__sum"] else 0
            current += interval
        labels = [label for label in sales_data]
        values = [sales_data[label] for label in sales_data]
        start = start.strftime("%Y-%m-%d %H:%M")
        end = end.strftime("%Y-%m-%d %H:%M")
    else:
        start = end = "2022-12-01 00:00"
        labels = values = []
    items = Item.objects.values("name").annotate(dcount=Count("name")).all()

    template = loader.get_template("home/manager/order_trends.html")
    context = {
        "forecast": forecast,
        "start": start,
        "end": end,
        "items": items,
        "labels": labels,
        "values": values,
    }
    return HttpResponse(template.render(context, request))

def menu(request):
    """gets menu data"""
    if request.method == 'POST':
        request.session['category'] = request.POST.get('category')
    else:
        request.session.flush()

    request.session.modified = True
    template = loader.get_template("home/menu/index.html")

    if 'category' not in request.session:
         request.session['category'] = Item.objects.order_by('category').values('category').annotate(dcount=Count('category'))[0]['category']
    categories = [category['category'] for category in Item.objects.order_by('category').values('category').annotate(dcount=Count('category'))]
    items = Item.objects.order_by('name').filter(category=request.session['category'])
    images = {}
    for item in items:
        if item.item_id < 129:
            images[item.item_id] = f"tea/{item.item_id // 3}.jpg"
        else:
            images[item.item_id] = "tea/custom.jpg"
    context = {
        'forecast': forecast,
        'categories': categories,
        'items': items,
        'images': images
    }
    return HttpResponse(template.render(context, request))

def customer_index(request):
    """gets menu items for customer to add"""
    # template = loader.get_template("home/customer/index.html")
    if request.method == 'POST':
        if request.POST.get("place_order"):
            #checking to see if there are enough ingredients to place an order
            total_ingredients_required = {}

            for item in request.session.get('order_items', []):
                itemid = item.split(',')[0]
                for item_ingredient in ItemsIngredient.objects.filter(item_id=itemid):
                    total_ingredients_required[item_ingredient.ingredient_id] = (
                        total_ingredients_required.get(item_ingredient.ingredient_id, 0)
                        + item_ingredient.amount
                    )

                ignore_augmentation_ids = [20, 21, 22, 23, 24] # Ice
                for augmentation in request.session.get('order_item_augs', []):
                    if augmentation[0] == item and augmentation[1] not in ignore_augmentation_ids:
                        augmentation_obj = Augmentation.objects.get(augmentation_id=augmentation[1])
                        total_ingredients_required[augmentation_obj.ingredient_id] = (
                            total_ingredients_required.get(augmentation_obj.ingredient_id, 0)
                            + augmentation_obj.amount
                        )
            item_ids_in_session = [item.split(',')[0] for item in request.session['order_items']]
            items = Item.objects.filter(item_id__in=item_ids_in_session).order_by('category')
            for ingredient_id, required_amount in total_ingredients_required.items():
                ingredient = Ingredient.objects.get(ingredient_id=ingredient_id)
                if ingredient.amount < required_amount:
                    total_price=0
                    context = {
                        'forecast': forecast,
                        'items': items,
                        'total_price': total_price,
                        'message': 'Cannot place order due to insufficient ingredients.',
                    }
                    template = loader.get_template("home/cashier/edit_cart.html")
                    return HttpResponse(template.render(context, request))
            thread = Thread(target = place_order, args = (request, False, ))
            thread.start()
        elif request.POST.get("category"):
            request.session['category'] = request.POST.get("category")
        else:
            ice_level = int(request.POST.get('ice'))
            sweetness_level = int(request.POST.get('sweetness'))
            milk_level = int(request.POST.get('milk'))
            milk_type = int(request.POST.get('milktype'))
            toppings = [int(i) for i in request.POST.getlist('toppings')]
            augmentations = [ice_level, sweetness_level, milk_type * 5 + milk_level, *tuple(toppings)]
            if 'order_items' not in request.session:
                request.session['order_items'] = []
            item_id = f"{request.session['item_id']},{len(request.session['order_items'])}"
            request.session['order_items'].append(item_id)
            if 'order_item_augs' not in request.session:
                request.session['order_item_augs'] = []
            if 'total_price' not in request.session:
                request.session['total_price'] = 0
            request.session['total_price'] += Item.objects.get(item_id=request.session['item_id']).price
            for aug in augmentations:
                request.session['total_price'] += Augmentation.objects.get(augmentation_id=aug).price
            for augmentation_id in augmentations:
                request.session['order_item_augs'].append((item_id, augmentation_id))
    else:
        request.session.flush()

    if 'category' not in request.session:
         request.session['category'] = Item.objects.order_by('category').values('category').annotate(dcount=Count('category'))[0]['category']
    request.session.modified = True
    template = loader.get_template("home/customer/index.html")
    categories = [category['category'] for category in Item.objects.order_by('category').values('category').annotate(dcount=Count('category'))]
    items = Item.objects.order_by('name').filter(category=request.session['category'])
    images = {}
    for item in items:
        if item.item_id < 129:
            images[item.item_id] = f"tea/{item.item_id // 3}.jpg"
        else:
            images[item.item_id] = "tea/custom.jpg"
    context = {
        'forecast': forecast,
        'categories': categories,
        'images': images,
        'items': items,
    }
    return HttpResponse(template.render(context, request))

#
def manager_edit_menu(request):
    """Modify ingredient specification within a menu item by clicking on it."""
    if redirect_logged_out(request):
        return redirect_logged_out(request)
    if request.method == 'POST':
        if request.POST.get('update_item'):
            updated_amounts = [float(i) for i in request.POST.getlist('ingredient_input')]
            item_id = request.session['item_id']
            item = Item.objects.get(item_id = item_id)
            item.category = request.POST.get('category')
            item.name = request.POST.get('item_name')
            item.size = request.POST.get('size')
            item.price = request.POST.get('price')
            item.save()
            for i in range(len(updated_amounts)):
                amount = updated_amounts[i]
                item_ingredient = ItemsIngredient.objects.filter(item=item, ingredient=i)
                item_ingredient = item_ingredient[0] if len(item_ingredient) else 0
                if item_ingredient:
                    item_ingredient.amount = amount
                    item_ingredient.save()
                elif amount:
                    ingredient = Ingredient.objects.get(ingredient_id=i)
                    item_ingredient = ItemsIngredient(
                        pair_id = len(ItemsIngredient.objects.all()),
                        item = item,
                        ingredient_id = i,
                        amount = amount,
                        unit = ingredient.unit
                    )
                    item_ingredient.save()
            request.session.flush()
            request.session['logged_in'] = True
            request.modified = True
        elif request.POST.get('category'):
            request.session['category'] = request.POST.get('category')
    else:
        request.session.flush()
        request.session['logged_in'] = True

    if 'category' not in request.session:
         request.session['category'] = Item.objects.order_by('category').values('category').annotate(dcount=Count('category'))[0]['category']
    template = loader.get_template("home/manager/edit_menu.html")
    categories = [category['category'] for category in Item.objects.order_by('category').values('category').annotate(dcount=Count('category'))]
    items = Item.objects.order_by('name').filter(category=request.session['category'])
    context = {
        'forecast': forecast,
        'items': items,
        'categories': categories,
    }

    return HttpResponse(template.render(context, request))

#
def manager_add_item(request):
    """Add a new item to the menu. Specify ingredients and amounts."""
    if redirect_logged_out(request):
        return redirect_logged_out(request)
    if request.method == "POST":
        # Handle the form submission
        name,size = tuple(request.POST.get("item").split(","))
        id = Item.objects.filter(name=name,size=size)[0].item_id
        request.session['item_id'] = id
        request.session.modified = True
        item_ingredients_list = ItemsIngredient.objects.order_by('ingredient__name').filter(item_id = id)

        item = Item.objects.get(item_id = id)
    else:
        item_ingredients_list = []
        item = Item(len(Item.objects.all()), "", "Tea", 0, 0)
        item.save()
        request.session['item_id'] = item.item_id
        request.session.modified = True

    ingredients = Ingredient.objects.order_by('ingredient_id').all()
    item_ingredients_dict = {}
    for item_ingredient in item_ingredients_list:
        item_ingredients_dict[item_ingredient.ingredient.name] = item_ingredient.amount

    template = loader.get_template("home/manager/add_item.html")

    context = {
        'forecast': forecast,
        'ingredients': ingredients,
        'item_ingredients': item_ingredients_dict,
        'item': item
    }

    return HttpResponse(template.render(context, request))

def redirect_logged_out(request):
    if 'logged_in' not in request.session or not request.session['logged_in']:
        return redirect("/")
    else:
        return None

def place_order(request, logged_in):
    order_items = []
    order_item_augs = []
    if 'order_items' in request.session:
        order_items = request.session['order_items']
    if 'order_item_augs' in request.session:
        order_item_augs = request.session['order_item_augs']
    request.session.flush()
    if logged_in:
        request.session['logged_in'] = True
    order = Order(len(Order.objects.all()), None, datetime.now())
    order.save()
    for item in order_items:
        order_item = OrdersItem(
            len(OrdersItem.objects.all()),
            order.order_id,
            item.split(',')[0],
            None
        )

        order_item.save()
        for augmentation in order_item_augs:
            if augmentation[0] == item:
                order_item_aug = OrdersItemsAugmentation(
                    len(OrdersItemsAugmentation.objects.all()),
                    order_item.pair_id,
                    augmentation[1]
                )
                order_item_aug.save()

    for item in order_items:
        itemid = item.split(',')[0]
        print("itemid:", itemid) #getting the correct item id
        ingredients_used = ItemsIngredient.objects.filter(item_id=itemid)
        print("ingre:", ingredients_used)
        for ingredient_used in ingredients_used:
            print("Ingredient ID:", ingredient_used.ingredient_id)
            print("Amount used:", ingredient_used.amount)
            ingredient = Ingredient.objects.get(ingredient_id=ingredient_used.ingredient_id)
            print(ingredient.amount)
            ingredient.amount -= ingredient_used.amount
            ingredient.recommended_fill_level += ingredient_used.amount
            ingredient.save()

        ignore_augmentation_ids = [20,21,22,23,24] #ice
        for augmentation in order_item_augs:
            print("order_item_augs:", order_item_augs)
            if augmentation[0] == item:
                print("augmentation[0]:",augmentation[0],item)
                aug_id = augmentation[1]
                print("aug_id",aug_id)
                if aug_id in ignore_augmentation_ids:
                    continue
                augmentation_obj = Augmentation.objects.get(augmentation_id=aug_id)
                ingredient = Ingredient.objects.get(ingredient_id=augmentation_obj.ingredient_id)
                ingredient.amount -= augmentation_obj.amount
                ingredient.recommended_fill_level += augmentation_obj.amount
                ingredient.save()


import pickle
import matplotlib.pyplot as plt
import numpy as np

res = pickle.load(open("/local/results/sb3.p", 'rb'))
dia = res.dmat_dia
hst = plt.hist(dia, 100)

maxx = np.max(hst[1])
maxy = np.max(hst[0])

perc = res.params.st2['memory']['smoothing_percentile']
x = np.percentile(dia, perc)

plt.plot((x,x), (0, maxy), 'r')

res.plot_delta()


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from vk_fetching import GetGroupInfoById

def GetBarPlot(measure, agg, l):
    fig, ax = plt.subplots()
    ax.bar(l.index, l[measure][agg], color = 'red')
    fig.set_figwidth(16)
    fig.set_figheight(6)
    ax.set_xlabel('Месяцы')
    if measure == 'post_views':
        if agg == 'mean':
            ax.set_ylabel('Среднее кол-во просмотров')
        else:
            ax.set_ylabel('Суммарное кол-во просмотров')
    elif measure == 'post_likes':
        if agg == 'mean':
            ax.set_ylabel('Среднее кол-во лайков')
        else:
            ax.set_ylabel('Суммарное кол-во лайков')
    elif measure == 'post_comments':
        if agg == 'mean':
            ax.set_ylabel('Среднее кол-во комментариев')
        else:
            ax.set_ylabel('Суммарное кол-во комментариев')
    else:
        if agg == 'mean':
            ax.set_ylabel('Среднее кол-во репостов')
        else:
            ax.set_ylabel('Суммарное кол-во репостов')
    plt.savefig('png/'+measure+agg+'.png')
    # plt.show(block=False)

def get_group_stats(group):

    post_data = GetGroupInfoById(group)

    df = pd.DataFrame(post_data)

    df['post_dt'] = pd.to_datetime(df['post_dt'])
    df['post_date'] = df['post_dt'].map(lambda x: x.strftime('%Y-%m-%d'))
    df['post_ym'] = df['post_dt'].map(lambda x: x.strftime('%Y-%m'))

    mean_day_posts = round(df.groupby(['post_date'])['post_id'].count().mean())
    mean_month_posts = round(df.groupby(['post_ym'])['post_id'].count().mean())
    mean_likes = round(df['post_likes'].mean())
    mean_reposts = round(df['post_reposts'].mean())
    mean_comments = round(df['post_comments'].mean())
    mean_views = round(df['post_views'].mean())
    conv_views_to_likes = round((mean_likes/mean_views)*100, 2)

    # print('------------------------')
    # print('Среднее кол-во постов в день:',mean_day_posts)
    # print('Среднее кол-во постов в месяц:',mean_month_posts)
    # print('Среднее кол-во лайков под постом:',mean_likes)
    # print('Среднее кол-во репостов под постом:',mean_reposts)
    # print('Среднее кол-во комментариев под постом:',mean_comments)
    # print('Среднее кол-во просмотров под постом:',mean_views)
    # print('Конверсия просмотров к лайкам:',conv_views_to_likes)

    l = df.groupby(['post_ym']).agg({'post_views':['sum', 'mean'], 'post_likes':['sum', 'mean'], 'post_comments':['sum', 'mean'], 'post_reposts':['sum', 'mean']})

    return_list = {
        'mean_day_posts':mean_day_posts,
        'mean_month_posts':mean_month_posts,
        'mean_likes':mean_likes,
        'mean_reposts':mean_reposts,
        'mean_comments':mean_comments,
        'mean_views':mean_views,
        'conv_views_to_likes':conv_views_to_likes
    }

    return return_list

    # GetBarPlot('post_views', 'mean')
    # GetBarPlot('post_views', 'sum')
    # GetBarPlot('post_comments', 'mean')
    # GetBarPlot('post_comments', 'sum')
    # GetBarPlot('post_likes', 'mean')
    # GetBarPlot('post_likes', 'sum')
    # GetBarPlot('post_reposts', 'mean')
    # GetBarPlot('post_reposts', 'sum')
    # print('Графики сохранены в папку png/')


def molecular_weight(atoms):
    r'''Calculates molecular weight of a molecule given a dictionary of its
    atoms and their counts, in the format {symbol: count}.

    .. math::
        MW = \sum_i n_i MW_i

    Parameters
    ----------
    atoms : dict
        dictionary of counts of individual atoms, indexed by symbol with
        proper capitalization, [-]

    Returns
    -------
    MW : float
        Calculated molecular weight [g/mol]

    Notes
    -----
    Elemental data is from rdkit, with CAS numbers added. An exception is
    raised if an incorrect element symbol is given. Elements up to 118 are
    supported, as are deutreium and tritium.

    Examples
    --------
    >>> molecular_weight({'H': 12, 'C': 20, 'O': 5}) # DNA
    332.30628

    References
    ----------
    .. [1] RDKit: Open-source cheminformatics; http://www.rdkit.org
    '''
    MW = 0
    for i in atoms:
        if i in periodic_table:
            MW += periodic_table[i].MW*atoms[i]
        elif i == 'D':
            # Hardcoded MW until an actual isotope db is created
            MW += 2.014102*atoms[i]
        elif i == 'T':
            # Hardcoded MW until an actual isotope db is created
            MW += 3.0160492*atoms[i]
        else:
            raise Exception('Molecule includes unknown atoms')
    return MW


'''
CG-SENSE reconstruction

Original author: Bruno Riemenschneider
First created: Jan. 3. 2022

Modifier: Jinho Kim
Email: jinho.kim@fau.de
Last update: Dec. 7. 2022
'''
import numpy as np
import scipy.io
import torch
import torchkbnufft as tkbn
from tqdm.auto import tqdm

from cg_sense_dist import cg_sense
from utils_dist import *

DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")

if __name__ == "__main__":
    mat = scipy.io.loadmat('data_radial_brain_4ch.mat')
    kspace = mat['kdata']
    sens_maps = mat['c']
    traj = mat['k']  # range of traj: -0.5~0.5
    ds_comp = mat['w']
    gt = mat['img_senscomb']
    N_ro, N_spokes, N_ch = kspace.shape

    DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    print(DEVICE)

    # 2.1 print trajectory
    plt.plot(traj[:, :].real, traj[:, :].imag)
    plt.title('k-space trajectory (64 spokes)')
    plt.show()

    kspace_T = kspace.transpose(2,0,1)
    sens_maps_t = sens_maps.transpose(2,0,1)
    imshow1row([kspace_T[1,:,:], sens_maps_t[1,:,:]], titles=['Radial kdata (channel 1)',  'rx coil sensitivity map (channel 1)'], isMag=True, norm=0.2)

    # 2.2 Simple regridding operation with NUFFT operator

    im_size = gt.shape
    grid_size = (N_ro, N_ro)
    # set nufft objects
    nufft_ob = tkbn.KbNufft(im_size=im_size, grid_size=grid_size, device=DEVICE)
    adjnufft_ob = tkbn.KbNufftAdjoint(im_size=im_size, grid_size=grid_size, device=DEVICE)

    # convert params to tensor objects
    traj_nufft = traj * 2 * np.pi
    traj_torch = torch.tensor(np.stack((traj_nufft.real.flatten(), traj_nufft.imag.flatten()), axis=0), device=DEVICE)
    smaps = torch.tensor(sens_maps.transpose(2, 0, 1)[None, ...], device=DEVICE)
    k_dcomp = kspace.copy()
    k_dcomp = kspace * ds_comp[..., None]
    k_dcomp = torch.tensor(k_dcomp.transpose(2, 0, 1).reshape(kspace.shape[-1], -1)[None,...], device=DEVICE)

    # nufft recon results
    nufft_recon = adjnufft_ob(k_dcomp, traj_torch, smaps=smaps)
    imshow1row([gt, torch.squeeze(nufft_recon).cpu().numpy()], titles=['GT','NUFFT reconstruction'])

    # Grad decent algorithm

    t = 3E-2
    u = torch.zeros(nufft_recon.shape, dtype=nufft_recon.dtype, device = DEVICE)
    k = torch.zeros(u.shape, dtype=u.dtype, device=DEVICE)
    kdata = torch.tensor(kspace.transpose(2,0,1).reshape(kspace.shape[-1], -1)[None, ...], device=DEVICE)
    iterations = 300
    recons = []
    kdata_evolve = []
    mse = []
    l2 = []
    error_loss = []
    with tqdm(total=iterations, unit='iter', leave=True, colour='green') as pbar:
        for i in range(iterations):
            grad = 2 * adjnufft_ob(
                                   nufft_ob(u, traj_torch, smaps=smaps, norm='ortho') - kdata,
                                   traj_torch,
                                    smaps=smaps,
                                    norm='ortho')
            u = u - t * grad
            k = ifft2c(torch.squeeze(u).cpu().numpy())
            np.power(k, 0.3, k)

            pbar.set_description(desc=f'Iteration {i:3d}')
            pbar.update()
            recons.append(abs(torch.squeeze(u).cpu().numpy()))
            kdata_evolve.append(abs(k))

            MSE = np.square(np.subtract(abs(normalize_img(gt)), abs(normalize_img(recons[len(recons) - 1])))).mean()
            mse.append(MSE)
            l2_loss = np.sqrt(np.sum(np.square(abs(normalize_img(gt)) - abs(normalize_img(recons[len(recons) - 1])))))
            error_loss.append(0.01*l2_loss)
            L2_grad = grad.norm(p=2)
            l2.append(L2_grad*0.1)

    creat_gif(recons, 'GD 300-Iterations', duration=50)
    creat_gif(kdata_evolve, 'GD k-data 300-Iterations', duration=50,)
    imshow1row(recons[-1:], titles=[f'GD recon at iteration {iterations}'])
    imshow1row(kdata_evolve[-1:], titles=[f'GD k-space at iteration {iterations}'], isMag=True)
    imshow1row([gt, torch.squeeze(nufft_recon).cpu().numpy(),recons[len(recons) - 1]], titles=['GT', 'Regridded', 'GD iterations=300'])
    e = diff_images(abs(normalize_img(gt)), [abs(normalize_img(torch.squeeze(nufft_recon).cpu().numpy())),abs(normalize_img(recons[len(recons) - 1]))])
    imshow1row(e, titles=['Regridded error', 'GD iterations=300 error'])
    plt.plot(range(0, iterations), mse)
    plt.plot(range(0, iterations), l2)
    #plt.plot(range(0, iterations), error_loss)
    plt.xlabel('Epoch')
    plt.ylabel('Metric values')
    plt.title('GD algorithm convergence')
    plt.legend(['mse', '0.1 * (L2 norm)'])
    plt.grid()
    plt.show()


from src.objects import board
from src.windows import layout_board
import PySimpleGUI as sg
import os
import csv

def show_game() :

    chess_board = board.Board()
    squares = chess_board.get_squares()
    board_window = layout_board.build(squares)
    selected_piece = False
    path_file = os.path.join(os.getcwd(),"src","files","games","")
    with open(path_file+"game_26.csv", "r", newline='', encoding="utf-8") as moves:
        game_movements = list(csv.reader(moves))[0]
    while True :
        event, values = board_window.read(timeout=500)
        if event in ("-EXIT-", sg.WIN_CLOSED) :
            break
        if len(game_movements) != 0 :
            event = game_movements.pop(0)
        if event.isnumeric() :
            if not selected_piece and squares[int(event)].is_occupied() and chess_board.get_turn(squares[int(event)].get_piece()) :
                board_window[str(event)].update(button_color="#E74C3C")
                last_event = event
                selected_piece = True
                if squares[int(event)].is_occupied() :
                    movements = squares[int(event)].get_piece().get_legal_movements(squares)
                    chess_board.show_movements(movements, board_window)
            elif selected_piece :
                chess_board.hide_movements(board_window)
                chess_board.move_piece(int(last_event), int(event), board_window)
                selected_piece = False
    board_window.close()

show_game()


# encoding: utf8
from SmallScrewdriver import BinPacking, DEFAULT_BIN_SIZE
from MaxRectsBin import MaxRectsBin

class MaxRectsBinPacking(BinPacking):
    def __init__(self, bin_size=DEFAULT_BIN_SIZE, images=None, bin_parameters=None):

        # Оставляем только изображения входящие по размеру в контейнер
        images = filter(lambda image: image.crop.size.less(bin_size) == (True, True), images)

        BinPacking.__init__(self,
                            bin_size=bin_size,
                            images=images,
                            bin_parameters=bin_parameters)

    def _newBin(self, size, bin_parameters):
        self.bins.append(MaxRectsBin(size, bin_parameters))
        return self.bins[-1]


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

import json
import requests
from urllib.parse import urljoin
from urllib import request

BASE_URL = 'http://192.168.26.67:8000'
AUTH = ('admin', 'admin')

def test_get_user_list():
    rsp = requests.get(urljoin(BASE_URL, '/snippets/'), auth=AUTH, headers={
        'Accept': 'application/json'
    })
    return rsp

def test_post_user_list():
    json_data = dict(
        title='zhangsan',
        code='oo',
        linenos='true'
    )
    rsp = requests.post(urljoin(BASE_URL, '/snippets/'), auth=AUTH, headers={
        'Accept': 'application/json',
        'Content-Type': 'application/json',
    }, data=json.dumps(json_data))
    return rsp

def test_get_user():
    rsp = requests.get(urljoin(BASE_URL, '/snippets/17'), auth=AUTH, headers={
        'Accept': 'application/json',
        'Content-Type': 'application/json',
    })
    return rsp

def test_put_user():
    json_data = dict(
        title='zhangsan',
        code='oo',
        linenos='true'
    )
    # 注意最后的 /
    rsp = requests.put(urljoin(BASE_URL, '/snippets/1/'), auth=AUTH, headers={
        'Accept': 'application/json',
        'Content-Type': 'application/json',
    }, data=json.dumps(json_data),
                       )
    return rsp

def test_patch_user():
    json_data = dict(
        title='aaaaaaaaaaaaaaaaaaaa',
    )
    rsp = requests.patch(urljoin(BASE_URL, '/snippets/1/'), auth=AUTH, headers={
        'Accept': 'application/json',
        'Content-Type': 'application/json',
    }, data=json.dumps(json_data),
                         )
    return rsp

def call(body, url):
    headers = {}

    # 这里有个细节，如果body需要json形式的话，需要做处理
    # 可以是data = json.dumps(body)
    response = requests.post(url, data=json.dumps(body), headers=headers)
    # 也可以直接将data字段换成json字段，2.4.3版本之后支持
    # response  = requests.post(url, json = body, headers = headers)

    # 返回信息
    print(response.text)
    # 返回响应头
    print(response.status_code)
    return "回调发送成功"

if __name__ == "__main__":
    url = "http://192.168.0.128:8080/api/register/result"
    data = '[{"bugid": "12260", "type": "success", "bugname": "firefox"}, {"bugid": "12261", "type": "success", "bugname": "xulrunner"}, {"bugid": "12262", "type": "failed", "bugname": "xulrunner-devel"}]'
    call(data, url)
    request.urlopen('http://www.sina.com.cn')
    # r = requests.get("http://localhost:9999/helloworld/yourname")
    # print(r.text)


# !/usr/bin/python3
# -*- coding: utf-8 -*-
"""
@Author         :  Zed
@Version        :  V1.0.0
------------------------------------
@File           :  42_queue.py
@Description    :
@CreateTime     :  2020-5-8 16:04
------------------------------------
@ModifyTime     :
"""
from queue import Queue
# 创建一个队列:可以让原本有序的东西，在出队的过程中保持原来的顺序
queue_num = Queue()
for i in range(200):
    # 入队操作
    queue_num.put(i)
# while not queue_num.empty():
#     # 出队
#     print(queue_num.get())
for i in range(1000):
    print(queue_num.get(block=False)) # block = False ，表示get方法为非阻塞方法，当队列为空的时候就抛出异常，
    # block = True 是默认情况，表示方法为阻塞方法，当队列为空，就阻塞当前线程


import requests

url = "https://api.linkedin.com/v2/me"

headers = {
    'Authorization': "Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    }

response = requests.request("GET", url, headers=headers)
import json
print(response.json())
obj = response.json()
print(obj['firstName']['localized']['en_US'],obj['lastName']['localized']['en_US'])


""" mass_spectrometer.py: for a MassSpectrometer class

Classes:
MassSpectromter -- representing a mass spectrometer

Constants:
WALL_THICKNESS -- thickness of walls, in pixels
WALL_COLOR -- color of walls
"""

import pygame
import charged_particle

# required initialization step
pygame.init()

# wall constants
WALL_THICKNESS = 10
WALL_COLOR = pygame.Color(148, 134, 106)

class MassSpectrometer():
    """A class to represent a mass spectrometer.

    Attributes:
    e_field -- electric field strength, positive is down
    mag_field -- magnetic field strength, positive is out of page
    _mass -- mass of charged particle
    _charge -- charge of charged particle
    _initial_x_velocity -- x velocity of charged particles at launch
    _area -- rectangular area that mass spectrometer takes up
    _particle -- current charged particle in mass spectrometer
    _walls -- list of Rects which are the walls of the mass spectrometer

    Methods:
    move -- move particle a frame
    draw -- draws the mass spectrometer on a Surface
    reset_particle -- reset the charged particle back to start
    set_mass -- sets _mass to a new value
    set_charge -- sets _charge to a new value
    set_initial_x_velocity -- sets initial x velocity to a new value
    """

    def __init__(self, e_field: int, mag_field: int, mass: int, charge: int,
                 initial_x_velocity: int, area: pygame.Rect):
        """Initialize a MassSpectrometer.

        e_field -- electric field strength, positive is down
        mag_field -- magnetic field strength, positive is out of page
        mass -- mass of charged particle
        charge -- charge of charged particle
        initial_x_velocity -- x velocity of charged particles at launch
        area -- rectangular area that mass spectrometer takes up
        """

        self.e_field = e_field
        self.mag_field = mag_field

        # save information about particle
        self._mass = mass
        self._charge = charge
        self.set_initial_x_velocity(initial_x_velocity)

        self._area = area

        # generate new particle
        self.reset_particle()
        self._walls = self._generate_walls(area)

    def _generate_walls(self, area: pygame.Rect) -> (pygame.Rect, pygame.Rect,
                                                     pygame.Rect, pygame.Rect):
        """Create properly-placed walls.

        2/5 from top/bottom to a horizontal wall, 1/5 between them
        1/2 of horizontal space goes to horizontal walls
        verticle walls sprout out from ends of horizontal ones

        area -- rectangular area that the mass spectrometer may take up

        Returns tuple with all walls as Rects
        """

        upper_horizontal = pygame.Rect(
            area.left, area.top + (2 * area.height / 5) - (WALL_THICKNESS / 2),
            (area.width / 2) - (WALL_THICKNESS / 2), WALL_THICKNESS)
        lower_horizontal = pygame.Rect(
            area.left, area.top + (3 * area.height / 5) - (WALL_THICKNESS / 2),
            (area.width / 2) - (WALL_THICKNESS / 2), WALL_THICKNESS)
        upper_vertical = pygame.Rect(
            area.left + (area.width / 2) - (WALL_THICKNESS / 2), 0,
            WALL_THICKNESS, 2 * area.height / 5)
        lower_vertical = pygame.Rect(
            area.left + (area.width / 2) - (WALL_THICKNESS / 2),
            3 * area.height / 5, WALL_THICKNESS, 2 * area.height / 5)

        return (upper_horizontal, lower_horizontal,
                upper_vertical, lower_vertical)

    def move(self):
        """Move particle one frame."""

        # electric field only works in first half (horizontal section)
        if (self._particle.get_pos()[0] >
            self._area.left + (self._area.width / 2)):
            self._particle.move(0, self.mag_field)
        else:
            self._particle.move(self.e_field, self.mag_field)

    def draw(self, screen: pygame.Surface):
        """Draw mass spectrometer onto a given Surface."""

        # draw particle
        self._particle.draw(screen)

        # draw each wall
        for wall in self._walls:
            pygame.draw.rect(screen, WALL_COLOR, wall)
            # particle stops if it hits a wall
            if self._particle.is_collision(wall):
                self._particle.stop()

        # particle stops if it hits the top or bottom edge
        particle_y = self._particle.get_pos()[1]
        if (particle_y < self._area.top or
            particle_y > self._area.top + self._area.height):
            self._particle.stop()

    def reset_particle(self):
        """Reset particle back to start position."""

        self._particle = charged_particle.ChargedParticle(
            self._mass, self._charge, self._initial_x_velocity,
            (charged_particle.RADIUS, self._area.height / 2))

    def set_mass(self, new_mass: int):
        """Update mass."""

        self._particle.set_mass(new_mass)
        # must also save to self for resetting purposes
        self._mass = new_mass

    def set_charge(self, new_charge: int):
        """Update charge."""

        self._particle.set_charge(new_charge)
        # must also save to self for resetting purposes
        self._charge = new_charge

    def set_initial_x_velocity(self, new_initial_x_velocity: int):
        """Update initial x velocit, checking if new value is legal."""

        if new_initial_x_velocity > 0:
            self._initial_x_velocity = new_initial_x_velocity
        else:
            raise ValueError("Initial x velocity must be positive")


from selenium import webdriver
from selenium.webdriver.common.keys import Keys

browser = webdriver.Chrome()
# driver.get("https://www.baidu.com")
# driver.implicitly_wait(10)
#
# js = 'window.open("");'
# driver.execute_script(js)
#
# driver.get("https://www.tezign.com")

browser.get('https://www.tezign.com')

# 获取当前窗口句柄（窗口A）
handle = browser.current_window_handle

# 打开一个新的窗口
js = 'window.open("");'
browser.execute_script(js)

# 获取当前所有窗口句柄（窗口A、B）
handles = browser.window_handles

# 对窗口进行遍历
for newhandle in handles:
    # 筛选新打开的窗口B
    if newhandle!=handle:
        # 切换到新打开的窗口B
        # browser.switch_to_window(newhandle) 旧版本
        browser.switch_to.window(newhandle)

        # 在新打开的窗口B中操作
        browser.get('https://www.baidu.com')

        # 关闭当前窗口B
        browser.close()

        #切换回窗口A
        browser.switch_to.window(handles[0])


# Databricks notebook source
import requests
import pandas as pd
from datetime import datetime
today = datetime.now().strftime('%Y_%m_%d_%H_%M_%S')
import random
import mlflow

api_key = ''
client_id = ''
headers = {'Authorization': 'Bearer {}'.format(api_key)}

def get_business(term, location):
  df = pd.DataFrame()
  today = datetime.now().strftime('%Y_%m_%d_%H_%M_%S')
  url = 'https://api.yelp.com/v3/businesses/search'

  for offset in range(0, 1000, 50):
    params = {'limit': 50, 'location': location.replace(' ', '+'), 'offset': offset, 'term': term.replace(' ', '+')
              }

    response = requests.get(url = url, headers=headers, params=params)

    def join_categories(df):
      vals=[]
      for key,item in enumerate(df):
        vals.append(item['alias'])

      return '|'.join(vals)

    if response.status_code == 200:

      tmp = pd.json_normalize(response.json()['businesses'])
      tmp['cats'] = tmp['categories'].apply(lambda x: join_categories(x))
      tmp_reduced = tmp[['id','name','review_count','rating','cats']]

      df = df.append(tmp_reduced,ignore_index=True)

    elif response.status_code == 400:
      print('400 Bad Request')
      break

  print(f"length of businesses returned: {len(df['id'])}")
  return df.sort_values(by='rating', ascending=False)

def filter_business(df, min_rating = 1):
  ''' df ---> list() of ids '''

  return df[df['rating'] >= min_rating][['id','name','rating','cats']]

def get_reviews(biz_df):
  review_df = pd.DataFrame()

  for id in biz_df['id'].values:

    #http request
    url = f'https://api.yelp.com/v3/businesses/{id}/reviews'
    response = requests.get(url = url,headers=headers)
    r = response.json()
    try:
      resp = pd.json_normalize(r['reviews'])

      #appending new cols to review df
      resp['name'] = biz_df[biz_df['id'] == id]['name'].iat[0]
      resp['rating'] = biz_df[biz_df['id'] == id]['rating'].iat[0]
      resp['cats'] = biz_df[biz_df['id'] == id]['cats'].iat[0]
      resp = resp[['id','name','text','rating','cats']]
      review_df = review_df.append(resp, ignore_index=True)

    except KeyError:
      print('key error')
      continue

  return review_df

def inputstream(term, location, minimum_rating):

  biz = get_business(term,location)
  biz_rev = get_reviews(biz)

  return biz_rev

# COMMAND ----------

import time

#due to API caps i incurred during the day, i will mimic calls using incremental copies instead

def start_class_demo():
  for n in range(1,939):
    time.sleep(1)
    dbutils.fs.cp(f'dbfs:/yelp_dump/file-{n}.json',f'dbfs:/yelp_dump/class_demo/file-{n}.json.json')

def class_demo_cleanup():
  dbutils.fs.rm('dbfs:/yelp_dump/class_demo',recurse=True)

def stop_all_streams():
  for stream in spark.streams.active:
    print(f"Stopping {stream.name}")
    stream.stop() # Stop the stream

# COMMAND ----------


import gspread
import pandas as pd

class GoogleSheet:
    is_spread_worksheet_set = False

    def __init__(
        self,
        service_account_file: str = "service_account.json",
        spreadsheet: str = None,
    ) -> None:
        self.sa = gspread.service_account(service_account_file)
        self.sh = None

        if spreadsheet:
            self.set_spread_worksheet(spreadsheet)

    def set_spread_worksheet(self, spreadsheet: str) -> None:
        self.sh = self.sa.open(spreadsheet)
        self.is_spread_worksheet_set = True

    def get_sheet(self, sheet: str) -> pd.DataFrame:
        if not self.is_spread_worksheet_set:
            raise ValueError(
                "Spreadsheet worksheet has not been set. Call set_spread_worksheet first."
            )
        wks = self.sh.worksheet(sheet)
        data = wks.get_all_values()
        return pd.DataFrame(data[1:], columns=data[0])


# Groupby collect as list
import polars as pl

# Create a DataFrame
df = pl.DataFrame({
    'group': ['A', 'A', 'B', 'B', 'A', 'B'],
    'value': [1, 2, 3, 4, 5, 6]
})

# Group by 'group' column and collect 'value' column as a list in a new column 'value_list'
grouped_df = df.groupby('group').agg(pl.col('value').alias('value_list'))

# Display the grouped DataFrame
print(grouped_df)

# Filter groupbed df by list:
import polars as pl

# Create a list of values with duplicate entries
my_list = [[1, 2, 3], [4, 5], [6, 7, 8, 9], [1, 2, 3], [4, 5], [6, 7, 8, 9],[99,0]]

# Create a Polars series from the list
list_column = pl.Series("list_column", my_list)

# Create the dataframe
loss_df = pl.DataFrame({
    'column1': [1, 2, 3, 4, 5, 6,9],
    'list_column': list_column
})

# Define the values to filter
filter_values = [5]

# Filter the dataframe using a lambda function
filtered_df = loss_df.filter(pl.col("list_column").apply(lambda list_val: any(elem in filter_values for elem in list_val)))

# Display the filtered dataframe
print(filtered_df)

# import polars as pl
#
# # Create a DataFrame with a column of lists
# loss_df = pl.DataFrame({
#     "column_name": [[1, 2, 3], [4, 5], [6, 7, 8, 9]],
#     "new_column3": [True, False, True],
#     "new_column4": [0.5, 1.2, 2.3],
#     "new_column5": ["X", "Y", "Z"],
#     "new_column6": [False, True, False]
# })
#
# # Explode the column of lists into rows
# exploded_data = loss_df.explode("column_name")
#
# # Print the resulting DataFrame
# print(exploded_data)


import variables
import pygame
import math
import Ammo

ammoColors = [(127, 255, 212), (227, 207, 87), (0, 0, 255), (152, 245, 255), (255, 97, 3), (220, 20, 60)]

class Tower:
    # Constructor
    def __init__(self, lvl, position, image, costOfUpgrade=20):
        self.lvl = lvl  # Tower lvl
        realPos = (position[0] - variables.TILE_SIZE / 2 + 2.5, position[1] - variables.TILE_SIZE / 2) #Real pos on window
        self.position = realPos # positon
        self.image = image #iamge of tower
        self.costOfUpgrade = costOfUpgrade # cost Of upgrade
        self.lastShot = pygame.time.get_ticks() # last shot time
        self.currentShot = self.lastShot # timer

    def getPosition(self): # return position
        return self.position

    def draw(self, window): # draw tower
        window.blit(self.image, self.position)

    def update(self): # update physics
        self.currentShot = pygame.time.get_ticks() # update timer
        closestEnemy = self.findClosestEnemy() # find closest enemy

        if not closestEnemy == None and self.currentShot - self.lastShot > variables.towerShootDelay: # if enemy exists and enough time passed:
            checkMinDistance = math.dist(self.position, closestEnemy.getPosition()) <= variables.towerRange # if enemy in range
            if checkMinDistance:
                self.shoot(closestEnemy) # shoot
                self.lastShot = self.currentShot # update last shoot time

    def upgrade(self, picture): # upgrade tower
        self.lvl += 1
        self.image = picture

    def getLvl(self): # get level
        return self.lvl

    def shoot(self, enemy):
        multi = self.lvl / 2 # upgrade multiplier
        if multi < 1:
            multi = 1
        # create bullet:
        ammoToCreate = Ammo.Ammo(self.position, enemy, variables.ammoSpeed * multi + 1, variables.ammoDamage * multi + 1, ammoColors[self.lvl - 1])
        # add bullet to ammos[] array:
        variables.ammos.append(ammoToCreate)

    def findClosestEnemy(self):
        if len(variables.enemies) > 0: # if enemies are on map
            bestEnemy = variables.enemies[0] # get first
            for enemy in variables.enemies: # iterate
                # if closest enemy exists -> replace current
                if math.dist(bestEnemy.getPosition(), self.position) > math.dist(enemy.getPosition(), self.position):
                    bestEnemy = enemy
            return bestEnemy # return enemy
        else:
            return None


#Vaughn and Charlie's I2C setup
import time
import RPi.GPIO as GPIO

#Setup LSM303
import Adafruit_LSM303
lsm303 = Adafruit_LSM303.LSM303()

#Setup SSD1306
import Adafruit_SSD1306
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

RST = 24
disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST, i2c_address=0x3D)
disp.begin()
disp.clear()
disp.display()
width = disp.width
height = disp.height
image = Image.new('1', (width, height))
draw = ImageDraw.Draw(image)
font = ImageFont.load_default()

while(True):
	#Clear the display
	#Print header
	draw.text((0, 0), 'ACCELEROMETER DATA',  font=font, fill=255)
	# Read the X, Y, Z axis acceleration values and print them.
	accel, mag = lsm303.read()
	# Grab the X, Y, Z components from the reading and print them out.
	accel_x, accel_y, accel_z = accel
	mag_x, mag_y, mag_z = mag
	xFloat = float(accel_x)/100
	#Prints X, Y, Z, to display
	draw.text((0, 20),('X: {}'.format(accel_x/100)), font=font, fill=255)
	draw.text((0, 30),('Y: {}'.format(accel_y/100)), font=font, fill=255)
	draw.text((0, 40),('Z: {}'.format(accel_z/100)), font=font, fill=255)
	# Wait half a second and repeat.
	time.sleep(0.5)
	#Display
	disp.image(image)
	disp.display()
	disp.clear()
	draw.rectangle((0,0,width,height), outline=0, fill=0)


# This file is where game logic lives. No input
# or output happens here. The logic in this file
# should be unit-testable.

import random
import sys
import numpy as np
from itertools import cycle

class Game:
    def __init__ (self, player_1, player_2):
        """Initializes a game with default settings"""

        # sets players as in selected mode
        self.players = cycle((player_1, player_2))
        self.player = next(self.players)

        # sets clear board and winner info
        self.board = None
        self.make_empty_board()
        self.winner = None
        self.count = 0
        self.resume = False

    def make_empty_board (self):
        """Initializes an empty board to start the game."""

        self.board = np.empty((3, 3), object)

    def print_board (self):
        """Prints the current status of the board and total scores."""

        # convert the board for better display
        # no need for modification if data structure saves 0 rather than None
        mod_board = [col if col else " " for row in self.board for col in row]

        print(f"\n\nTic-tac-toe Scoreboard\n\n"
              f"\t  {mod_board[0]} | {mod_board[1]} | {mod_board[2]}  \n"
              f"\t ———|———|——— \t\n"
              f"\t  {mod_board[3]} | {mod_board[4]} | {mod_board[5]}  \n"
              f"\t ———|———|——— \t\n"
              f"\t  {mod_board[6]} | {mod_board[7]} | {mod_board[8]}  \n"
              f"\nCurrent winner: {self.winner}\n")

    def get_winner (self):
        """Determines the winner of the given board.
        Returns 'X', 'O', or None."""

        # convert text strings to int values for easier calculation and comparison
        mod_board = [[-1 if ele == 'O' else 1 if ele == 'X' else 0 for ele in row]
                     for row in self.board]

        # sums of values in rows and columns of the board
        rows = [sum(i) for i in mod_board]
        columns = [sum(i) for i in zip(*mod_board)]

        # convert diagonal values to lists
        dec_diagonal = [mod_board[i][i] for i in range(len(mod_board))]
        inc_diagonal = [mod_board[i][len(mod_board) - 1 - i] for i in range(len(mod_board))]

        # concatenate sums of eight routes in a list for final check
        sum_temp = rows + columns + [sum(dec_diagonal)] + [sum(inc_diagonal)]

        # conditional result return based on the sum of each route
        return 'O' if -3 in sum_temp else 'X' if 3 in sum_temp else None

    def switch_player (self):
        """Toggle between two players."""

        self.player = next(self.players)

    def update_board (self, row, column):
        """Updates the board to reflect the move a player makes."""

        self.board[row][column] = self.player.symbol

    def play_game (self):
        """Runs the main body of the game after mode selection."""

        # game continues without a winner or a tie
        while not self.winner and self.count <= 9:
            # prompts move from player and updates to board
            row, column = self.player.get_move(self.board)
            self.update_board(row, column)

            # check winner after five total moves and prints scoreboard
            self.winner = self.get_winner() if self.count >= 5 else None
            self.print_board()
            if self.winner:
                # there is a winner
                print(f"Player {self.player.symbol} is the winner!\n")

            # switches player and increments count
            self.count += 1
            self.switch_player()

        if not self.winner:
            # there is a tie
            print(f"There's no winner. Try again!\n")

        self.new_game()

    def new_game (self):
        """Prompts the option to start a new game after completion."""

        while self.resume not in ['Y', 'N']:
            # sanity checks the input and changes the status of resume
            self.resume = input("Would you like a new game? Y for yes and N for no.\n")

        if self.resume == 'Y':
            # resets game status if user wants a new one
            self.reset_game()
        else:
            sys.exit("So long!")

    def reset_game (self):
        """Resets the game to its initial state."""

        self.board = None
        self.make_empty_board()
        self.winner = None
        self.count = 0
        self.resume = False

class Human:
    def __init__ (self, player):
        """Initializes a human player that inputs moves."""

        self.symbol = player

    def get_move (self, board):
        """Prompts the user to make the next move.
        Validates it and updates it to the board."""

        move = input(f"Make your move, fellow player {self.symbol}.\n")

        if not move.isdigit() or int(move) not in range(1, 10):
            # check if the input is the correct type
            print(f"Make your move as a numerical number in the range 1-9.")
            return self.get_move(board)
        else:
            move = int(move)

        # conversion from integer to 2d location
        row = int((move - 1) / 3)
        column = int((move - 1) % 3)

        if board[row][column]:
            # check if the move is on an available place of the board
            print(f"{move} is taken -- make your move in an available spot.")
            return self.get_move(board)

        # updates move to the board in Game class through an instance
        # board.update_board(row, column, self._player) how to make this work?
        return row, column

class Bot:
    def __init__ (self, player):
        """Initializes a bot player that takes random moves."""

        self.symbol = player

    def get_move (self, board):
        """Chooses a random spot to move from available candidates."""

        # algorithm for the bot to pick a random move from available spots
        avail = [(row, col) for row in range(3) for col in range(3) if not board[row][col]]
        selection = random.choice(avail)

        print(f"Player {self.symbol} made a move. Go!")

        # updates move to the board in Game class through an instance
        return selection[0], selection[1]


from flask_wtf import FlaskForm
from wtforms import StringField, IntegerField, SelectField, SubmitField

class StudentForm(FlaskForm):
    pic = StringField('Student Picture')
    id = StringField('Student ID')
    firstName = StringField('First Name')
    lastName = StringField('Last Name')
    course = StringField('Course')
    year = IntegerField('Year')  # IntegerField for numeric input
    gender = SelectField('Gender', choices=[('Male', 'Male'), ('Female', 'Female'), ('Non-binary', 'Non-binary'), ('Transgender',
                         'Transgender'), ('Prefer not to say', 'Prefer not to say'), ('Not listed', 'Not listed')])  # SelectField for dropdown input
    submit = SubmitField('Submit')  # Submit button field


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

from .misc import nested_tensor_from_tensor_list
from .backbone import build_backbone
from .transformer import build_transformer

class Pix2Seq(nn.Module):
    """ This is the Pix2Seq module that performs object detection """
    def __init__(self, backbone, transformer):
        """ Initializes the model.
        Parameters:
            backbone: torch module of the backbone to be used. See backbone.py
            transformer: torch module of the transformer architecture. See transformer.py
            num_classes: number of object classes
            num_bins: number of bins for each side of the input image
        """
        super().__init__()
        self.transformer = transformer
        hidden_dim = transformer.d_model
        self.input_proj = nn.Sequential(
            nn.Conv2d(backbone.num_channels, hidden_dim, kernel_size=(1, 1)),
            nn.GroupNorm(32, hidden_dim))
        self.backbone = backbone

    def forward(self, image_tensor, targets=None, max_len=500):
        """
        image_tensor:
        The forward expects a NestedTensor, which consists of:
           - samples.tensor: batched images, of shape [batch_size x 3 x H x W]
           - samples.mask: a binary mask of shape [batch_size x H x W], containing 1 on padded pixels
        It returns a dict with the following elements:
           - "pred_logits": the classification logits (including no-object) for all vocabulary.
                            Shape= [batch_size, num_sequence, num_vocal]
        """
        if isinstance(image_tensor, (list, torch.Tensor)):
            image_tensor = nested_tensor_from_tensor_list(image_tensor)
        features, pos = self.backbone(image_tensor)

        src, mask = features[-1].decompose()
        assert mask is not None
        mask = torch.zeros_like(mask).bool()

        src = self.input_proj(src)
        if targets is not None:
            input_seq, input_len = targets
            output_logits = self.transformer(src, input_seq[:, 1:], mask, pos[-1])
            return output_logits[:, :-1]
        else:
            output_seqs, output_scores = self.transformer(src, None, mask, pos[-1], max_len=max_len)
            return output_seqs, output_scores

def build_pix2seq_model(args, tokenizer):
    # the `num_classes` naming here is somewhat misleading.
    # it indeed corresponds to `max_obj_id + 1`, where max_obj_id
    # is the maximum id for a class in your dataset. For example,
    # COCO has a max_obj_id of 90, so we pass `num_classes` to be 91.
    # As another example, for a dataset that has a single class with id 1,
    # you should pass `num_classes` to be 2 (max_obj_id + 1).
    # For more details on this, check the following discussion
    # https://github.com/facebookresearch/detr/issues/108#issuecomment-650269223

    backbone = build_backbone(args)
    transformer = build_transformer(args, tokenizer)

    model = Pix2Seq(backbone, transformer)

    if args.pix2seq_ckpt is not None:
        checkpoint = torch.load(args.pix2seq_ckpt, map_location='cpu')
        model.load_state_dict(checkpoint['model'])

    return model


'''
-Hard-
*Backtracking*

You are given an integer array cards of length 4. You have four cards, each containing a number
in the range [1, 9]. You should arrange the numbers on these cards in a mathematical expression
using the operators ['+', '-', '*', '/'] and the parentheses '(' and ')' to get the value 24.

You are restricted with the following rules:

The division operator '/' represents real division, not integer division.
For example, 4 / (1 - 2 / 3) = 4 / (1 / 3) = 12.
Every operation done is between two numbers. In particular, we cannot use '-' as a unary operator.
For example, if cards = [1, 1, 1, 1], the expression "-1 - 1 - 1 - 1" is not allowed.
You cannot concatenate numbers together
For example, if cards = [1, 2, 1, 2], the expression "12 + 12" is not valid.
Return true if you can get such expression that evaluates to 24, and false otherwise.

Example 1:

Input: cards = [4,1,8,7]
Output: true
Explanation: (8-4) * (7-1) = 24
Example 2:

Input: cards = [1,2,1,2]
Output: false

Constraints:

cards.length == 4
1 <= cards[i] <= 9
'''

class Solution(object):
    def judgePoint24(self, cards):
        """
        :type cards: List[int]
        :rtype: bool
        """
        eps = 0.001
        def helper(nums, ops, eps):
            if len(nums) == 1: return abs(nums[0] - 24) < eps
            for i in range(len(nums)):
                for j in range(len(nums)):
                    if i == j: continue
                    t = []
                    for k in range(len(nums)):
                        if k != i and k != j: t.append(nums[k])
                    for op in ops:
                        #for '+' and '*', exchanging left and right operands gives
                        # the same answer, so we skip i > j iterations
                        if (op == '+' or op == '*') and i > j: continue
                        if op == '/' and nums[j] < eps: continue # prevent divide by zero
                        t.append(ops[op](nums[i], nums[j]))
                        if helper(t, ops, eps): return True
                        t.pop()
            return False
        ops = {'+': lambda x,y: x+y,
               '-': lambda x,y: x-y,
               '*': lambda x,y: x*y,
               '/': lambda x,y: x/y}
        return helper(cards, ops, eps)

    def judgePoint24Expression(self, cards):
        """
        :type cards: List[int]
        :rtype: bool
        """
        eps = 0.001
        self.ans = []
        def helper(nums, ops, eps, expr):
            if len(nums) == 1:
                if abs(nums[0] - 24) < eps:
                    self.ans.append(expr[0])
                    return True
                return False
            for i in range(len(nums)):
                for j in range(len(nums)):
                    if i == j: continue
                    t, e = [], []
                    for k in range(len(nums)):
                        if k != i and k != j:
                            t.append(nums[k])
                            e.append(expr[k])
                    for op in ops:
                        #for '+' and '*', exchanging left and right operands gives
                        # the same answer, so we skip i > j iterations
                        if (op == '+' or op == '*') and i > j: continue
                        if op == '/' and nums[j] < eps: continue # prevent divide by zero
                        t.append(ops[op](nums[i], nums[j]))
                        e.append('('+(expr[i] if expr[i] else str(nums[i]))
                                 +op+(expr[j] if expr[j] else str(nums[j]))+')')
                        if helper(t, ops, eps, e): return True
                        t.pop()
                        e.pop()
            return False
        ops = {'+': lambda x,y: x+y,
               '-': lambda x,y: x-y,
               '*': lambda x,y: x*y,
               '/': lambda x,y: x/y}
        if helper(cards, ops, eps, ['']*4):
            return self.ans

if __name__ == "__main__":
    print(Solution().judgePoint24([4,1,8,7]))
    print(Solution().judgePoint24Expression([4,1,8,7]))
    print(Solution().judgePoint24Expression([1,3,4,6]))
    print(Solution().judgePoint24Expression([7,7,7,10]))


'''
Created on Oct 1, 2015

@author: gary
'''

import regex as re
from processing.generic import *
from processing import SourceProcesor
from processing import handle_synonyms
import tag_phrase

def extract_inchoative(text):
    return re.sub('\b(make|cause to)\s+(.*)', r'\1')

def extract_article(text):
    return re.sub('\b(a|an|the)\s+(.*)', r'\1')

class ArticleFilter(SourceProcesor):
    def __init__(self):
        super(self.__class__, self).__init__()
        self.columns = ('eng',)

    @handle_synonyms
    def remove_article(self, text):
        return re.sub('^\s*(?:a|an|the)\s+(.*)$', r'\1', text)

    def run(self, entry):
        self.parent.run(entry)

        for lang in self.columns:
            fields = entry[lang]
            fields[0] = self.remove_article( fields[0])
            entry[lang] = fields

        return

class InfinitiveFilter(SourceProcesor):
    def __init__(self, pat='^to\M(?: be\s+)?(.*)$'):
        super(self.__class__, self).__init__()
        self.inf_pat = re.compile(pat)
        self.columns = ('eng',)

    @handle_synonyms
    def replace_infinitive(self, text):
        match = self.inf_pat.search(text)
        if match:
            text = self.inf_pat.sub(r'\1', text)

        return text

    def run(self, entry):
        self.parent.run(entry)

        for lang in self.columns:
            fields = entry[lang]
            start = fields
            fields[0] = self.replace_infinitive( fields[0])
            entry[lang] = fields

        return

class InchoativeFilter(SourceProcesor):
    def __init__(self, pat='^to(?: be\s+)?(.*)$'):
        super(self.__class__, self).__init__()
        self.inf_pat = re.compile(pat)
        self.columns = ('eng',)
        self.tagger = tag_phrase.get_tagger()

    #@handle_synonyms
    #def remove_inchoative(self, text):
    #    if tag_phrase
    #    return text

    def run(self, entry):
        self.parent.run(entry)

        for lang in self.columns:
            fields = entry[lang]
            fields[0] = self.remove_inchoative( fields[0])
            entry[lang] = fields

        return

class AuxFilter(SourceProcesor):
    def __init__(self):
        super(self.__class__, self).__init__()

    @handle_synonyms
    def replace_aux(self, text):
        text = text.strip()
        text = re.sub('^be ', '', text)
        text = re.sub('^(.*) of something$', r'\1 (of something)', text)
        text = re.sub('^(.*) something$', r'\1 (something)', text)
        text = re.sub('^(.*) someone$', r'\1 (someone)', text)
        text = re.sub('(.*) type$', r'(type of) \1', text)
        text = re.sub('(.*) type (\(.*\))(.*)$', r'(type of) \1 \2\3', text)
        return text

    def run(self, entry):
        self.parent.run(entry)

        for lang in self.columns:
            fields = entry[lang]
            fields[0] = self.replace_aux( fields[0])
            entry[lang] = fields

        return

class OrSplitFilter(SourceProcesor):
    def __init__(self):
        super(self.__class__, self).__init__()

    @process_method_outside_parens
    def split_on_or(self, text):
        if len(text.split()) == 3:
            result = re.sub('(?:,)? or ', '‣', text)
            return result
        else:
            return text

    def run(self, entry):
        self.parent.run(entry)

        for lang in self.columns:
            fields = entry[lang]
            fields[0] = self.split_on_or( fields[0])
            entry[lang] = fields

        return


import time
import heapq

def merge_sorted_lists(a,n):
    min_heap = [(size, [i]) for i, size in enumerate(a)]
    heapq.heapify(min_heap)

    total_cost = 0

    while len(min_heap) > 1:
        size1, list1 = heapq.heappop(min_heap)
        size2, list2 = heapq.heappop(min_heap)

        merged_list = list1 + list2
        merged_size = size1 + size2
        total_cost += merged_size

        # Limit the size of the merged list to `n`.
        if len(merged_list) > n:
            merged_list = merged_list[:n]
            merged_size = n

        heapq.heappush(min_heap, (merged_size, merged_list))

    merged_sequence = min_heap[0][1]

    return merged_sequence, total_cost

a = [3, 5, 2, 8]
n = 1000

merged_sequence, total_cost = merge_sorted_lists(a, n)

print("Merged sequence:", merged_sequence)
print("Total cost of merging:", total_cost)

start_time = time.time()
result = merge_sorted_lists(a, n)
end_time = time.time()
execution_time = end_time - start_time
execution_time_ns = execution_time * 1e9
print(f"Execution Time: {execution_time_ns:.6f} nanoseconds")


#!/usr/bin/env python

#
# Send direct message to user who requests it
#

#---Dependencies-------------
from discord import Client, Intents
from json import load

#---Parameters---------------
intents = Intents(messages=True, guilds=True, members=True)

#---Execution----------------
with open("config.json", "r") as json_file:
  secrets = load(json_file)
  class MyClient(Client):
    async def on_ready(self):
      print('Logged on as {0}!'.format(self.user))

    async def on_message(self, message):
      print('Message from {0.author}: {0.content}'.format(message))

      if "dm-me" in message.content:
        await message.author.send(content="Hello! Beep boop!")
        print('='*3)
        print('Direct message sent!')
        print('='*3)
      else:
        print("Command not recognized.")

  client = MyClient(intents=intents)
  client.run(secrets['token'])


import psutil,time, requests
import GPUtil
url = input('WebhookUrl >')
while True:
    gpus = GPUtil.getGPUs()
    for gpu in gpus:
        gpu_id = gpu.id
        gpu_name = gpu.name
        gpu_load = f"{gpu.load*100}%"
    x = psutil.cpu_percent()
    svmem = psutil.virtual_memory()
    def get_size(bytes, suffix="B"):
        factor = 1024
        for unit in ["", "K", "M", "G", "T", "P"]:
            if bytes < factor:
                return f"{bytes:.2f}{unit}{suffix}"
            bytes /= factor
    json = {
    "embeds": [
        {
        "description": f"CPU {x}%\nRAM {get_size(svmem.used)} GB\n GPU NAME\n{gpu.name}\nLoad%\n{gpu_load}",
        "color": 36007,
        "author": {
            "name": "CPU & RAM CHECK & GPU"
        }
        }
    ],
    "avatar_url": "https://scontent.fbkk29-1.fna.fbcdn.net/v/t39.30808-6/327658970_990618138567512_6512244974626364113_n.jpg?_nc_cat=100&ccb=1-7&_nc_sid=09cbfe&_nc_eui2=AeEDE55yQoWvdEvmo4uCEzqu8GsCEGp0ThHwawIQanROEdz8n-dLn-z_U5sqyk1Vv8_-O9TzF2v9hnEHU80AgvUN&_nc_ohc=dHgZkW6jJ8wAX-SV-4j&_nc_ht=scontent.fbkk29-1.fna&oh=00_AfC9Q70XHzEpzFH879zyfkwntleOJTzwY23jVwx6Jl5txA&oe=63EF0BB1",
    "attachments": []

    }
    respon = requests.post(url, json=json)
    print(respon)
    time.sleep(10)


# Crie uma função chamada media que aceite uma lista de números como parâmetro e retorne a média deles.

numeros = []

def media(numeros):
    soma = sum(numeros)
    med = soma / len(numeros)
    return med

while (1):
    x = int(input('Acrescente um número (0 para parar): '))
    if x == 0:
        break
    numeros.append(x)

print(f'Números: {numeros}')
print(f'Média: {media(numeros)}')

Python/FATEC/2° Semestre - Linguagem de Programação/Funções - Exercicios/ex-03.py


class Alumno():
    def __init__(self, nombre, nota):
        self.nombre = nombre
        self.nota = nota

    def mostrar(self):
        print(f"Nombre: {self.nombre}")
        print(f"Nota: {self.nota}")

    def valoracion(self):
        if self.nota < 5:
            print(f"{self.nombre} ha suspendido")
        else:
            print(f"{self.nombre} ha aprobado")

if __name__ == "__main__":
    alumno1 = Alumno("Lucia", 7)
    alumno2 = Alumno("Eva", 8)
    alumno3 = Alumno("Maria", 4)
    alumno1.mostrar()
    alumno1.valoracion()
    alumno2.mostrar()
    alumno2.valoracion()
    alumno3.mostrar()
    alumno3.valoracion()


from upyog.imports import *

def zip_folder(path: PathLike):
    path = Path(path)
    assert path.is_dir()
    assert path.exists()

    return shutil.make_archive(path, "zip", path)

def compose_files_into_zip_archive(
    files: List[PathLike],
    out_dir: PathLike,
    zip_name: str = "Archive",
):
    out_dir = Path(out_dir)
    out_dir.mkdir(exist_ok=True)
    zip_name = zip_name + ".zip"

    for file in files:
        shutil.copy(file, str(out_dir / zip_name))

    zipfile = zip_folder(out_dir)
    shutil.rmtree(out_dir)

    return zipfile


#automatic writing match op code to string script
import json

# Opening JSON file
with open('Opcodes.json') as json_file:
    data = json.load(json_file)["unprefixed"]
    print("match opcode {")
    for op in data:

        name = data[op]["mnemonic"]
        operands = data[op]["operands"]
        strr = f'{op} => println!("{name} '
        for operand in operands:
            strr += f' {operand["name"]} '

        strr += ' " ),'
        print(strr)
    print("}")


from plingo import Plingo

if __name__ == "__main__":
    lingo = Plingo()

    result = ""
    for idx, cmd in enumerate(sorted(lingo._command_names)):
        try:
            method = getattr(lingo, cmd)

            command = cmd[9:]

            doc = method.__doc__
            if not doc:
                doc = "_not yet documented_"

            result = f"{result}## {idx:03d} - {command} \n\n{doc} \n\n"
        except Exception:
            result = f"{result}## {idx:03d} - {command} \n\nNot implemented yet \n\n"

    print(result)


from flask import Flask, Blueprint, request, jsonify, Response, make_response
from models.GameModel import GameModel
from algos.NBAModel import NBAModel
from db import connect
from datetime import datetime
import pytz
from routes.responses import good_response, bad_response
import json
import pandas as pd
import requests
import io
from flask_cors import CORS, cross_origin

# Set the time zone to EST
est_tz = pytz.timezone('US/Eastern')

nba_blueprint = Blueprint('nba_blueprint', __name__)

@nba_blueprint.route('', methods=['GET'])
@cross_origin()
def get_games():
    # Connect to db
    connection = connect('games')
    # Get the current time in EST
    current_time_est = datetime.now(est_tz)
    formatted_time = str(current_time_est.strftime("%Y-%m-%d %I:%M:%S %p"))

    # get nba games
    games = list(connection.find({"sport": {'$eq': "nba"}}))
    data = []
    for element in games:
        element['_id'] = str(element['_id'])
        if datetime.strptime(element['date'], "%Y-%m-%d %I:%M:%S %p") > datetime.strptime(formatted_time, "%Y-%m-%d %I:%M:%S %p"):
            data.append(element)

    def sortDates(dict):
        return datetime.strptime(dict['date'], "%Y-%m-%d %I:%M:%S %p")

    data.sort(key=sortDates)

    try:
        return good_response(data)

    except Exception as e:
        return bad_response(e)

# API Call to retrieve historical data and update current games/bets/users to reflect final scores
@nba_blueprint.route('/update_games', methods=['GET', 'OPTIONS'])
@cross_origin()
def update_games():
    try:
        db_hard_start = datetime(2023, 11, 7)

        # URL of the data
        url = 'https://sportsdatabase.com/NBA/query?output=default&sdql=date%2C+team%2C+site%2C+o%3Ateam%2C+total%2C+line%2C+line%20ave%20odds%2C+money%20line%2C+total%20over%20ave%20odds%2C+total%20under%20ave%20odds%2C++points%2C+o%3Apoints+%40season%3E2019&submit=++S+D+Q+L+%21++'

        # Send an HTTP GET request to the URL and get the response content
        response = requests.get(url)

        if response.status_code == 200:
            # Convert the response content to JSON format
            data1 = response.json()

            column_names = data1['headers']
            column_data = data1['groups'][0]['columns']

            data_transposed = list(map(list, zip(*column_data)))

            # Create a Pandas DataFrame from the transposed data
            df = pd.DataFrame(data_transposed)

            # Optionally, set column names
            df.columns = column_names

        else:
            print('Failed to fetch the nba data.')

        # Date formatting, get rows before today
        new_df = df
        new_df['date'] = pd.to_datetime(new_df['date'], format='%Y%m%d')

        # Get today's date
        today = datetime.now()

        before_today_df = new_df

        # Rename columns
        before_today_df = before_today_df.rename(columns={'team': 'Home Team', 'o:team': 'Away Team','points': 'Score', 'o:points': 'Opp Score'})
        print(before_today_df)

        before_today_df = before_today_df.dropna()

        home_df = before_today_df[before_today_df['site'] == 'home']
        away_df = before_today_df[before_today_df['site'] == 'away']

        away_mls = away_df['money line'].tolist()
        away_lines = away_df['line'].tolist()
        away_lines_odds = away_df['line ave odds'].tolist()

        # Renaming
        home_df['Away Odds Close'] = away_mls
        home_df['Away Line Close'] = away_lines
        home_df['Away Line Odds Close'] = away_lines_odds

        home_df = home_df.rename(columns={'Score': 'Home Score', 'Opp Score': 'Away Score', 'date': 'Date', 'total': 'Total Score Close', 'money line': 'Home Odds Close', 'line': 'Home Line Close', 'line ave odds': 'Home Line Odds Close', 'total over ave odds' :'Total Score Over Close', 'total under ave odds' : 'Total Score Under Close'})
        # Drop the site column
        home_df = home_df.drop('site', axis=1)

        # Define a function to extract the last element from a list
        get_last_element = lambda x: x[-1]

        # Apply the function to the list columns
        home_df['Home Line Odds Close'] = home_df['Home Line Odds Close'].apply(get_last_element)
        home_df['Away Line Odds Close'] = home_df['Away Line Odds Close'].apply(get_last_element)
        home_df['Total Score Over Close'] = home_df['Total Score Over Close'].apply(get_last_element)
        home_df['Total Score Under Close'] = home_df['Total Score Under Close'].apply(get_last_element)

        # Even to +100
        home_df.loc[home_df['Home Odds Close'] == 'even', 'Home Odds Close'] = '100'
        home_df.loc[home_df['Away Odds Close'] == 'even', 'Away Odds Close'] = '100'

        # Function to convert American odds to decimal odds
        def american_to_decimal(american_odds):
            american_odds = pd.to_numeric(american_odds)  # Convert the string to numeric
            if american_odds > 0:
                return round((american_odds / 100) + 1, 2)
            elif american_odds < 0:
                return round((-100 / american_odds) + 1, 2)
            else:
                return 1  # Even (American odds of 0)

        # Apply the conversion function to the American Odds columns
        home_df['Home Odds Close'] = home_df['Home Odds Close'].apply(american_to_decimal)
        home_df['Away Odds Close'] = home_df['Away Odds Close'].apply(american_to_decimal)
        home_df['Home Line Odds Close'] = home_df['Home Line Odds Close'].apply(american_to_decimal)
        home_df['Away Line Odds Close'] = home_df['Away Line Odds Close'].apply(american_to_decimal)
        home_df['Total Score Over Close'] = home_df['Total Score Over Close'].apply(american_to_decimal)
        home_df['Total Score Under Close'] = home_df['Total Score Under Close'].apply(american_to_decimal)

        home_df['Total Score'] = home_df['Home Score'] + home_df['Away Score']

        # Change team names to be accurate
        nba_teams = {
            'Hawks': 'Atlanta Hawks',
            'Celtics': 'Boston Celtics',
            'Nets': 'Brooklyn Nets',
            'Hornets': 'Charlotte Hornets',
            'Bulls': 'Chicago Bulls',
            'Cavaliers': 'Cleveland Cavaliers',
            'Mavericks': 'Dallas Mavericks',
            'Nuggets': 'Denver Nuggets',
            'Pistons': 'Detroit Pistons',
            'Warriors': 'Golden State Warriors',
            'Rockets': 'Houston Rockets',
            'Pacers': 'Indiana Pacers',
            'Clippers': 'Los Angeles Clippers',
            'Lakers': 'Los Angeles Lakers',
            'Grizzlies': 'Memphis Grizzlies',
            'Heat': 'Miami Heat',
            'Bucks': 'Milwaukee Bucks',
            'Timberwolves': 'Minnesota Timberwolves',
            'Pelicans': 'New Orleans Pelicans',
            'Knicks': 'New York Knicks',
            'Thunder': 'Oklahoma City Thunder',
            'Magic': 'Orlando Magic',
            'Seventysixers': 'Philadelphia 76ers',
            'Suns': 'Phoenix Suns',
            'Trailblazers': 'Portland Trail Blazers',
            'Kings': 'Sacramento Kings',
            'Spurs': 'San Antonio Spurs',
            'Raptors': 'Toronto Raptors',
            'Jazz': 'Utah Jazz',
            'Wizards': 'Washington Wizards',
        }

        home_df['Home Team'] = home_df['Home Team'].map(nba_teams)
        home_df['Away Team'] = home_df['Away Team'].map(nba_teams)

        nba = NBAModel()
        nba.populateDB()

        # Function to format a date string from Mongo to excel format
        def convert_date_format(input_date):
            # Convert the input date string to a datetime object
            date_obj = datetime.strptime(input_date, '%Y-%m-%d %I:%M:%S %p')
            # Format the datetime object to '%Y-%m-%d' format
            formatted_date = date_obj.strftime('%Y-%m-%d')
            return formatted_date

        #Only keep rows after hard start
        filtered_df = home_df[home_df['Date'] > pd.to_datetime(db_hard_start)]
        print(filtered_df)

        # Update games in MongoDB with result
        connection = connect('games')

        # Get the current time in EST
        current_time_est = datetime.now(est_tz)
        formatted_time = str(current_time_est.strftime("%Y-%m-%d %I:%M:%S %p"))
        #print(formatted_time)
        data = list(connection.find({"$and": [{'date': {"$lt": formatted_time}}, {"sport": {'$eq': "nba"}}, {"home_score": {'$eq': None}}, {"away_score": {'$eq': None}}]}))
        for element in data:
            element['_id'] = str(element['_id'])
            row = filtered_df[(filtered_df['Date'] == convert_date_format(element['date'])) & (filtered_df['Home Team'] == element['home_team']) & (filtered_df['Away Team'] == element['away_team'])]
            print(row)
            if len(row.index) > 0:

                ### Updating home and away scores
                element['home_score'] = int(row['Home Score'].values[0])
                element['away_score'] = int(row['Away Score'].values[0])
                connection.update_one({'game_id': element['game_id']}, {'$set': {"home_score": element["home_score"]}, '$currentDate': { 'lastUpdated': True }} )
                connection.update_one({'game_id': element['game_id']}, {'$set': {"away_score": element["away_score"]}, '$currentDate': { 'lastUpdated': True }} )

                connection_to_users = connect('users')
                connection_to_bets = connect('bets')

                #Update bets
                game_bets = connection_to_bets.find({'game_id': element['game_id']})
                for bet in game_bets:
                    if bet['actual_payout'] is None:
                        payout = 0
                        # Away ML bet
                        if bet['bet_type'] == 'Away':
                            if element['away_score'] > element['home_score']:
                                payout = bet['potential_payout']
                            elif element['away_score'] < element['home_score']:
                                payout = 0
                            else:
                                payout = bet['wager']

                        # Home ML bet
                        elif bet['bet_type'] == 'Home':
                            if element['home_score'] > element['away_score']:
                                payout = bet['potential_payout']
                            elif element['home_score'] < element['away_score']:
                                payout = 0
                            else:
                                payout = bet['wager']

                        # Away Spread
                        elif bet['bet_type'] == 'Away Line':
                            if element['home_score'] - element['away_score'] < element['away_spread']:
                                payout = bet['potential_payout']
                            elif element['home_score'] - element['away_score'] > element['away_spread']:
                                payout = 0
                            else:
                                payout = bet['wager']
                        # Home Spread
                        elif bet['bet_type'] == 'Home Line':
                            if element['away_score'] - element['home_score'] < element['home_spread']:
                                payout = bet['potential_payout']
                            elif element['away_score'] - element['home_score'] > element['home_spread']:
                                payout = 0
                            else:
                                payout = bet['wager']
                        # Over
                        elif bet['bet_type'] == 'Over':
                            if element['away_score'] + element['home_score'] > element['total']:
                                payout = bet['potential_payout']
                            elif element['away_score'] + element['home_score'] < element['total']:
                                payout = 0
                            else:
                                payout = bet['wager']
                        #Under
                        elif bet['bet_type'] == 'Under':
                            if element['away_score'] + element['home_score'] < element['total']:
                                payout = bet['potential_payout']
                            elif element['away_score'] + element['home_score'] > element['total']:
                                payout = 0
                            else:
                                payout = bet['wager']
                        # Update Bet actual payout value
                        connection_to_bets.update_one({'_id': bet['_id']}, {'$set': {"actual_payout": payout}, '$currentDate': { 'lastUpdated': True }} )

                        # Update corresponding account balance and lifetime winnings
                        bet_account = list(connection_to_users.find({"username": bet['account_username']}))[0]
                        new_lifetime_winnings = float(bet_account['lifetime_winnings']) + float(payout)
                        new_current_balance = float(bet_account['current_balance']) + float(payout)
                        connection_to_users.update_one({'username': bet['account_username']}, {'$set': {"lifetime_winnings": new_lifetime_winnings}, '$currentDate': { 'lastUpdated': True }} )
                        connection_to_users.update_one({'username': bet['account_username']}, {'$set': {"current_balance": new_current_balance}, '$currentDate': { 'lastUpdated': True }} )

        return good_response("NBA Games were updated")

    except Exception as e:
        return bad_response(e)


import sys
import Lista_Serial
from PyQt5 import QtWidgets
from heat_flow_gui import Ui_MainWindow
from serial_reader import SerialReader

if __name__ == "__main__":
    serialReader = SerialReader
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    ui.preencher_portas_combobox(Lista_Serial.serial_ports())
    ui.attachInitializeEvent(serialReader.serial_read)
    ui.attachConnectEvent(serialReader.connect)
    ui.attachDisconnectEvent(serialReader.disconnect)
    MainWindow.show()
    sys.exit(app.exec_())