# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt

"""Tests for coverage.py's results analysis."""

from __future__ import annotations

import math

from typing import Dict, Iterable, List, Tuple, cast

import pytest

from coverage.exceptions import ConfigError
from coverage.results import format_lines, Numbers, should_fail_under
from coverage.types import TLineNo

from tests.coveragetest import CoverageTest

class NumbersTest(CoverageTest):
    """Tests for coverage.py's numeric measurement summaries."""

    run_in_temp_dir = False

    def test_basic(self) -> None:
        n1 = Numbers(n_files=1, n_statements=200, n_missing=20)
        assert n1.n_statements == 200
        assert n1.n_executed == 180
        assert n1.n_missing == 20
        assert n1.pc_covered == 90

    def test_addition(self) -> None:
        n1 = Numbers(n_files=1, n_statements=200, n_missing=20)
        n2 = Numbers(n_files=1, n_statements=10, n_missing=8)
        n3 = n1 + n2
        assert n3.n_files == 2
        assert n3.n_statements == 210
        assert n3.n_executed == 182
        assert n3.n_missing == 28
        assert math.isclose(n3.pc_covered, 86.666666666)

    def test_sum(self) -> None:
        n1 = Numbers(n_files=1, n_statements=200, n_missing=20)
        n2 = Numbers(n_files=1, n_statements=10, n_missing=8)
        n3 = cast(Numbers, sum([n1, n2]))
        assert n3.n_files == 2
        assert n3.n_statements == 210
        assert n3.n_executed == 182
        assert n3.n_missing == 28
        assert math.isclose(n3.pc_covered, 86.666666666)

    @pytest.mark.parametrize("kwargs, res", [
        (dict(n_files=1, n_statements=1000, n_missing=0), "100"),
        (dict(n_files=1, n_statements=1000, n_missing=1), "99"),
        (dict(n_files=1, n_statements=1000, n_missing=999), "1"),
        (dict(n_files=1, n_statements=1000, n_missing=1000), "0"),
        (dict(precision=1, n_files=1, n_statements=10000, n_missing=0), "100.0"),
        (dict(precision=1, n_files=1, n_statements=10000, n_missing=1), "99.9"),
        (dict(precision=1, n_files=1, n_statements=10000, n_missing=9999), "0.1"),
        (dict(precision=1, n_files=1, n_statements=10000, n_missing=10000), "0.0"),
    ])
    def test_pc_covered_str(self, kwargs: Dict[str, int], res: str) -> None:
        assert Numbers(**kwargs).pc_covered_str == res

    @pytest.mark.parametrize("prec, pc, res", [
        (0, 47.87, "48"),
        (1, 47.87, "47.9"),
        (0, 99.995, "99"),
        (2, 99.99995, "99.99"),
    ])
    def test_display_covered(self, prec: int, pc: float, res: str) -> None:
        assert Numbers(precision=prec).display_covered(pc) == res

    @pytest.mark.parametrize("prec, width", [
        (0, 3),     # 100
        (1, 5),     # 100.0
        (4, 8),     # 100.0000
    ])
    def test_pc_str_width(self, prec: int, width: int) -> None:
        assert Numbers(precision=prec).pc_str_width() == width

    def test_covered_ratio(self) -> None:
        n = Numbers(n_files=1, n_statements=200, n_missing=47)
        assert n.ratio_covered == (153, 200)

        n = Numbers(
            n_files=1, n_statements=200, n_missing=47,
            n_branches=10, n_missing_branches=3, n_partial_branches=1000,
        )
        assert n.ratio_covered == (160, 210)

@pytest.mark.parametrize("total, fail_under, precision, result", [
    # fail_under==0 means anything is fine!
    (0, 0, 0, False),
    (0.001, 0, 0, False),
    # very small fail_under is possible to fail.
    (0.001, 0.01, 0, True),
    # Rounding should work properly.
    (42.1, 42, 0, False),
    (42.1, 43, 0, True),
    (42.857, 42, 0, False),
    (42.857, 43, 0, False),
    (42.857, 44, 0, True),
    (42.857, 42.856, 3, False),
    (42.857, 42.858, 3, True),
    # If you don't specify precision, your fail-under is rounded.
    (42.857, 42.856, 0, False),
    # Values near 100 should only be treated as 100 if they are 100.
    (99.8, 100, 0, True),
    (100.0, 100, 0, False),
    (99.8, 99.7, 1, False),
    (99.88, 99.90, 2, True),
    (99.999, 100, 1, True),
    (99.999, 100, 2, True),
    (99.999, 100, 3, True),
])
def test_should_fail_under(total: float, fail_under: float, precision: int, result: bool) -> None:
    assert should_fail_under(float(total), float(fail_under), precision) == result

def test_should_fail_under_invalid_value() -> None:
    with pytest.raises(ConfigError, match=r"fail_under=101"):
        should_fail_under(100.0, 101, 0)

@pytest.mark.parametrize("statements, lines, result", [
    ({1,2,3,4,5,10,11,12,13,14}, {1,2,5,10,11,13,14}, "1-2, 5-11, 13-14"),
    ([1,2,3,4,5,10,11,12,13,14,98,99], [1,2,5,10,11,13,14,99], "1-2, 5-11, 13-14, 99"),
    ([1,2,3,4,98,99,100,101,102,103,104], [1,2,99,102,103,104], "1-2, 99, 102-104"),
    ([17], [17], "17"),
    ([90,91,92,93,94,95], [90,91,92,93,94,95], "90-95"),
    ([1, 2, 3, 4, 5], [], ""),
    ([1, 2, 3, 4, 5], [4], "4"),
])
def test_format_lines(
    statements: Iterable[TLineNo],
    lines: Iterable[TLineNo],
    result: str,
) -> None:
    assert format_lines(statements, lines) == result

@pytest.mark.parametrize("statements, lines, arcs, result", [
    (
        {1,2,3,4,5,10,11,12,13,14},
        {1,2,5,10,11,13,14},
        (),
        "1-2, 5-11, 13-14"
    ),
    (
        [1,2,3,4,5,10,11,12,13,14,98,99],
        [1,2,5,10,11,13,14,99],
        [(3, [4]), (5, [10, 11]), (98, [100, -1])],
        "1-2, 3->4, 5-11, 13-14, 98->100, 98->exit, 99"
    ),
    (
        [1,2,3,4,98,99,100,101,102,103,104],
        [1,2,99,102,103,104],
        [(3, [4]), (104, [-1])],
        "1-2, 3->4, 99, 102-104"
    ),
])
def test_format_lines_with_arcs(
    statements: Iterable[TLineNo],
    lines: Iterable[TLineNo],
    arcs: Iterable[Tuple[TLineNo, List[TLineNo]]],
    result: str,
) -> None:
    assert format_lines(statements, lines, arcs) == result


import heapq
from typing import List

class Solution:
    def lastStoneWeight(self, stones: List[int]) -> int:
        # simulate a MaxHeap with a MinHeap
        for i in range(len(stones)):
            stones[i] = -stones[i]

        heapq.heapify(stones)
        while len(stones) >= 2:
            diff = heapq.heappop(stones) - heapq.heappop(stones)
            if diff != 0:
                heapq.heappush(stones, diff)

        return -stones[0] if stones else 0

print(Solution().lastStoneWeight([2, 7, 4, 1, 8, 1]))  # 1


from rest_framework import generics, status
from authApp.models.fermentacion import Fermentacion
from rest_framework.response import Response

class FermentacionDeleteView(generics.DestroyAPIView):

    def delete(self, request):
        _id = self.request.query_params.get('id')
        fermentacion = Fermentacion.objects.filter(id=_id)
        fermentacion.delete()
        response = {
            'success': True,
            'statusCode': status.HTTP_200_OK,
            'message': 'Fermentacion eliminada',
        }
        return Response(response, status=status.HTTP_200_OK)


from matplotlib import ticker
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Daten aus CSV-Datei laden
df = pd.read_csv("data/Spotify_Youtube.csv")

# Entferne die URL-Spalten
url_cols = ["Url_spotify", "Uri", "Url_youtube", "Description"]
df.drop(url_cols, axis=1, inplace=True)

# Fülle fehlende Werte und entferne NaNs
df["Likes"] = df["Likes"].fillna(0)
df["Comments"] = df["Comments"].fillna(0)
df.dropna(inplace=True)

# Entferne Duplikate basierend auf Track
df.drop_duplicates(subset="Track", keep="first", inplace=True)

# Daten für den Scatter Plot extrahieren
likes = df["Likes"]
comments = df["Comments"]
views = df["Views"]

# Normalisiere die Größe der Punkte, damit sie besser sichtbar sind
max_views = views.max()
min_views = views.min()
normalized_sizes = (views - min_views) / (max_views - min_views) * 100

# Scatter Plot erstellen
plt.scatter(likes, comments, s=normalized_sizes, alpha=0.5, c=views, cmap="plasma")

# Achsenbeschriftungen
plt.xlabel("Likes in millions")
plt.ylabel("Comments in millions")

# Titel und Farblegende (der Titel wird um 1.05 Einheiten nach oben verschoben)
plt.title("Relation between likes, comments and views on YouTube", y=1.05)

# Anpassung der Skala für bessere Lesbarkeit (optional)
plt.xscale("linear")  # Lineare Skala für die x-Achse (Likes)
plt.yscale("linear")  # Lineare Skala für die y-Achse (Kommentare)

# Ganzzahlige Ticker-Formatierung für die Achsen
plt.gca().xaxis.set_major_locator(ticker.MaxNLocator(integer=True))
plt.gca().yaxis.set_major_locator(ticker.MaxNLocator(integer=True))

# Achsenticker-Formatierung für die Achsen in Millionen
def millions_formatter(x, pos):
    return "{:.1f}".format(x / 1e6)

# Achsenticker-Formatierung für die Achsen in Millionen
def billions_formatter(x, pos):
    return "{:.1f}".format(x / 1e9)

# Farblegende in Milliarden formatieren
colorbar = plt.colorbar(label="Views in billions")
colorbar.ax.yaxis.set_major_formatter(ticker.FuncFormatter(billions_formatter))

plt.gca().xaxis.set_major_formatter(ticker.FuncFormatter(millions_formatter))
plt.gca().yaxis.set_major_formatter(ticker.FuncFormatter(millions_formatter))

# Zeige den Plot
plt.tight_layout()
plt.show()


import urllib.request, urllib.parse, urllib.error
import xml.etree.ElementTree as ET

url = input("Enter URL - ")
xml = urllib.request.urlopen(url).read().decode()
print('Retrieving', url)
print('Retrieved', len(xml),'characters')
tree = ET.fromstring(xml)
#print(xml)
lst = tree.findall('.//count')
total = 0
count = 0
for item in lst:
    total += int(item.text)
    count += 1
print('Count:', count)
print('Sum:', total)


''' createDB.py
This file is used to Create the tables in the SQLite database once data_log.db
has been created. It can also be used to delete any existing data in tables.
'''
# package needed for sql
import sqlite3 as sqlite

# databse file
dbFile = '/home/pi/python/assignment1/data_log.db'

# open the database
connection = sqlite.connect(dbFile)
cursor = connection.cursor()

with connection:
    # drop the tables if they already exist
    cursor.execute("DROP TABLE IF EXISTS temp_and_humid")
    cursor.execute("DROP TABLE IF EXISTS accel_and_orient")
    cursor.execute("DROP TABLE IF EXISTS bluetooth_devices")

    # create the temperature and humidity table
    cursor.execute("CREATE TABLE temp_and_humid (\n" +
                   "date_time datetime PRIMARY KEY,\n" +
                   "temperature NUMERIC,\n" +
                   "humidity NUMERIC)"
                   )

    # create the accelerometer and orientation table
    cursor.execute("CREATE TABLE accel_and_orient (\n" +
                   "date_time datetime PRIMARY KEY,\n" +
                   "x NUMERIC,\n" +
                   "y NUMERIC,\n" +
                   "z NUMERIC,\n" +
                   "pitch NUMERIC,\n" +
                   "roll NUMERIC,\n" +
                   "yaw NUMERIC)"
                    )

    # create table for found bluetooth devices
    cursor.execute("CREATE TABLE bluetooth_devices (\n" +
                  "date_time datetime PRIMARY KEY,\n" +
                  "mac_address TEXT,\n" +
                  "device_name TEXT)"
                  )

print('Database Schema created successfully.')


from pathlib import Path
from typing import List

INPUT_FILE = Path(__file__).with_suffix(".input")

GROOVES = [1000, 2000, 3000]
KEY = 811589153
P2_COUNT = 10

def solve(seq: List[int], count: int = 1) -> int:
    moved_list = [i for i in range(len(seq))]
    for n in list(moved_list) * count:
        i = moved_list.index(n)
        moved_list.pop(i)
        new_index = (seq[n] + i) % len(moved_list)
        if new_index == 0:
            moved_list.append(n)
        else:
            moved_list.insert(new_index, n)
    zero_index = moved_list.index(seq.index(0))
    grooves = [seq[moved_list[(i + zero_index) % len(moved_list)]] for i in GROOVES]
    return sum(grooves)

if __name__ == "__main__":
    DATA = INPUT_FILE.read_text().strip()
    CODE = [int(line) for line in DATA.split("\n")]

    print(solve(CODE))
    print(solve([i * KEY for i in CODE], 10))


from setuptools import setup, find_packages
from codecs import open
from os import path
here = path.abspath(path.dirname(__file__))

with open(path.join(here, 'README.md'), encoding='utf-8') as f:
    long_description = f.read()

setup(
    name='messagemedia_lookups_sdk',
    version='1.0.0',
    description='The MessageMedia Lookups API provides a number of endpoints for validating the phone numbers you’re sending to by checking their validity, type and carrier records.',
    long_description=long_description,
    author='MessageMedia Developers',
    author_email='developers@messagemedia.com',
    url='https://developers.messagemedia.com',
    packages=find_packages(),
    install_requires=[
        'requests>=2.9.1, <3.0',
        'jsonpickle>=0.7.1, <1.0',
        'cachecontrol>=0.11.7, <1.0',
        'python-dateutil>=2.5.3, <3.0'
    ],
    tests_require=[
        'nose>=1.3.7'
    ],
    test_suite = 'nose.collector'
)


from pydantic import BaseModel, Field, validator

from typing import Dict, List, Sequence

class TextStyleParameters(BaseModel):
    """Text style parameters"""
    fill: str = Field(..., description="Text fill color")
    fontSize: int = Field(..., description="Text font size")
    fontFamily: str = Field(..., description="Text font family")
    align: str = Field(..., description="Text alignment")
    verticalAlign: str = Field(..., description="Text vertical alignment")

    def __init__(self, fill, fontSize, fontFamily, align, verticalAlign):
        super().__init__(
            fill=fill,
            fontSize=fontSize,
            fontFamily=fontFamily,
            align=align,
            verticalAlign=verticalAlign,
        )

    @validator("fill")
    def fill_must_be_hex(cls, v):
        if not v.startswith("#"):
            print("ERROR: Fill must be a hex value: ", v)
            return "#000000"
        return v

    @validator("fontSize")
    def font_size_must_be_positive(cls, v):
        if v <= 0 or type(v) != int:
            print("ERROR: Font size must be positive: ", v)
            return 12
        return v

    @validator("fontFamily")
    def font_family_must_be_valid(cls, v):
        if v not in ["Arial", "Times New Roman", "Courier New"]:
            print("ERROR: Font family not supported: ", v)
            return "Arial"
        return v

    @validator("align")
    def align_must_be_valid(cls, v):
        if v not in ["left", "center", "right"]:
            print("ERROR: Align not supported: ", v)
            return "left"
        return v

    @validator("verticalAlign")
    def vertical_align_must_be_valid(cls, v):
        if v not in ["top", "middle", "bottom"]:
            print("ERROR: Vertical align not supported: ", v)
            return "top"
        return v

class BackgroundParameters(BaseModel):
    """Text background parameters"""
    fill: str = Field(..., description="Text background fill color")
    alpha: float = Field(..., description="Text background alpha")

    def __init__(self, fill, alpha):
        super().__init__(
            fill=fill,
            alpha=alpha,
        )

    @validator("fill")
    def fill_must_be_hex(cls, v):
        if not v.startswith("#"):
            print("ERROR: Fill must be a hex value: ", v)
            return "#ffffff"
        return v

    @validator("alpha")
    def alpha_must_be_between_zero_and_one(cls, v):
        if v < 0 or v > 1 or type(v) != float:
            print("ERROR: Alpha must be between 0 and 1: ", v)
            return 1
        return v

class StrokeParameters(BaseModel):
    """Text stroke parameters"""
    width: int = Field(..., description="Text stroke width")
    fill: str = Field(..., description="Text stroke fill color")
    alpha: float = Field(..., description="Text stroke alpha")

    def __init__(self, width, fill, alpha):
        super().__init__(
            width=width,
            fill=fill,
            alpha=alpha,
        )

    @validator("width")
    def width_must_be_positive(cls, v):
        if v <= 0 or type(v) != int:
            print("ERROR: Width must be positive: ", v)
            return 2
        return v

    @validator("fill")
    def fill_must_be_hex(cls, v):
        if not v.startswith("#"):
            print("ERROR: Fill must be a hex value: ", v)
            return "#000000"
        return v

    @validator("alpha")
    def alpha_must_be_between_zero_and_one(cls, v):
        if v < 0 or v > 1 or type(v) != float:
            print("ERROR: Alpha must be between 0 and 1: ", v)
            return 1
        return v

class StarParameters(BaseModel):
    """Shape star parameters"""
    numPoints: int = Field(..., description="Number of points in star")
    innerRadius: int = Field(..., description="Inner radius of star")

    def __init__(self, numPoints, innerRadius):
        super().__init__(
            numPoints=numPoints,
            innerRadius=innerRadius,
        )

    @validator("numPoints")
    def num_points_must_be_at_least_2(cls, v):
        if v < 2 or type(v) != int:
            print("ERROR: Number of points must be at least 2: ", v)
            return 5
        return v

    @validator("innerRadius")
    def inner_radius_must_be_positive(cls, v):
        if v <= 0 or type(v) != int:
            print("ERROR: Inner radius must be positive: ", v)
            return 100
        return v

class TextParameters(BaseModel):
    """Text edit parameters"""
    content: str = Field(..., description="Text content")
    style: TextStyleParameters = Field(..., description="Text style")
    background: BackgroundParameters = Field(..., description="Text background")

    def __init__(self, content, style, background):
        style = TextStyleParameters(**style)
        background = BackgroundParameters(**background)
        super().__init__(
            content=content,
            style=style,
            background=background,
        )

    @validator("content")
    def content_must_be_string(cls, v):
        if not isinstance(v, str):
            print("ERROR: Content must be a string: ", v)
            return "Text"
        return v

class ImageParameters(BaseModel):
    """Image edit parameters"""
    source: str = Field(..., description="Image source")
    searchQuery: str = Field(..., description="Image search query")

    def __init__(self, source, searchQuery):
        super().__init__(
            source=source,
            searchQuery=searchQuery,
        )

    @validator("source")
    def source_must_be_link_or_directory(cls, v):
        if not v.startswith("http") and not v.startswith("/"):
            print("ERROR: Source must be a link or directory: ", v)
            return "/placeholder.jpg"

    @validator("searchQuery")
    def search_query_must_be_string(cls, v):
        if not isinstance(v, str):
            print("ERROR: Search query must be a string: ", v)
            return ""
        return v

class ShapeParameters(BaseModel):
    """Shape background parameters"""
    type: str = Field(..., description="Shape type")
    background: BackgroundParameters = Field(..., description="Shape background")
    stroke: StrokeParameters = Field(..., description="Shape stroke")
    star: StarParameters = Field(..., description="Shape star parameters")

    def __init__(self, type, background, stroke, star):
        background = BackgroundParameters(**background)
        stroke = StrokeParameters(**stroke)
        star = StarParameters(**star)
        super().__init__(
            type=type,
            background=background,
            stroke=stroke,
            star=star,
        )

    @validator("type")
    def type_must_be_valid(cls, v):
        if v not in ["rectangle", "circle", "star"]:
            print("ERROR: Type must be rectangle, circle, or star: ", v)
            return "rectangle"
        return v

class ZoomParameters(BaseModel):
    """Zoom edit parameters"""
    zoomDurationStart: int = Field(..., description="Zoom duration start")
    zoomDurationEnd: int = Field(..., description="Zoom duration end")

    def __init__(self, zoomDurationStart, zoomDurationEnd):
        super().__init__(
            zoomDurationStart=zoomDurationStart,
            zoomDurationEnd=zoomDurationEnd,
        )

    @validator("zoomDurationStart")
    def zoom_duration_start_must_be_nonnegative(cls, v):
        if v < 0 or type(v) != int:
            print("ERROR: Zoom duration start must be positive: ", v)
            return 0
        return v

    @validator("zoomDurationEnd")
    def zoom_duration_end_must_be_nonnegative(cls, v):
        if v < 0 or type(v) != int:
            print("ERROR: Zoom duration end must be positive: ", v)
            return 0
        return v

class CropParameters(BaseModel):
    """Crop edit parameters"""
    x: int = Field(..., description="Crop x")
    y: int = Field(..., description="Crop y")
    width: int = Field(..., description="Crop width")
    height: int = Field(..., description="Crop height")
    cropX: int = Field(..., description="Crop x")
    cropY: int = Field(..., description="Crop y")
    cropWidth: int = Field(..., description="Crop width")
    cropHeight: int = Field(..., description="Crop height")

    def __init__(self, x, y, width, height, cropX, cropY, cropWidth, cropHeight):
        super().__init__(
            x=x,
            y=y,
            width=width,
            height=height,
            cropX=cropX,
            cropY=cropY,
            cropWidth=cropWidth,
            cropHeight=cropHeight,
        )

    @validator("width")
    def width_must_be_nonnegative(cls, v):
        if type(v) != int or v < 0:
            print("ERROR: Width must be positive: ", v)
            return 100
        return v

    @validator("height")
    def height_must_be_nonnegative(cls, v):
        if type(v) != int or v < 0:
            print("ERROR: Height must be positive: ", v)
            return 100
        return v

    @validator("cropWidth")
    def crop_width_must_be_nonnegative(cls, v):
        if type(v) != int or v < 0:
            print("ERROR: Crop width must be positive: ", v)
            return 100
        return v

    @validator("cropHeight")
    def crop_height_must_be_nonnegative(cls, v):
        if type(v) != int or v < 0:
            print("ERROR: Crop height must be positive: ", v)
            return 100
        return v

class BlurParameters(BaseModel):
    """Blur edit parameters"""
    blur: int = Field(..., description="Blur")

    def __init__(self, blur):
        super().__init__(
            blur=blur,
        )

    @validator("blur")
    def blur_must_be_positive(cls, v):
        if type(v) != int or v <= 0:
            print("ERROR: Blur must be positive: ", v)
            return 0
        return v

class CutParameters(BaseModel):
    """Cut edit parameters"""
    pass

class EditParameters(BaseModel):
    """All Edit Parameters together"""

    textParameters: TextParameters = Field(..., description="Text edit parameters")
    # imageParameters: ImageParameters = Field(..., description="Image edit parameters")
    shapeParameters: ShapeParameters = Field(..., description="Shape edit parameters")
    blurParameters: BlurParameters = Field(..., description="Blur edit parameters")
    # cutParameters: CutParameters = Field(..., description="Cut edit parameters")
    # cropParameters: CropParameters = Field(..., description="Crop edit parameters")
    zoomParameters: ZoomParameters = Field(..., description="Zoom edit parameters")

    def __init__(
        self,
        textParameters,
        # imageParameters,
        shapeParameters,
        blurParameters,
        # cutParameters,
        # cropParameters,
        zoomParameters,
    ):
        super().__init__(
            textParameters=textParameters,
            # imageParameters=imageParameters,
            shapeParameters=shapeParameters,
            blurParameters=blurParameters,
            # cutParameters=cutParameters,
            # cropParameters=cropParameters,
            zoomParameters=zoomParameters,
        )

    def get_parameters(self):
        return {
            "textParameters": self.textParameters,
            # "imageParameters": self.imageParameters,
            "shapeParameters": self.shapeParameters,
            "blurParameters": self.blurParameters,
            # "cutParameters": self.cutParameters,
            # "cropParameters": self.cropParameters,
            "zoomParameters": self.zoomParameters,
        }

    def get_parameters_short(self):
        return {
            "text": self.textParameters,
            # "image": self.imageParameters,
            "shape": self.shapeParameters,
            "blur": self.blurParameters,
            # "cut": self.cutParameters,
            # "crop": self.cropParameters,
            "zoom": self.zoomParameters,
        }

    @classmethod
    def get_instance(cls, textParameters={}, imageParameters={}, shapeParameters={}, blurParameters={}, cutParameters={}, cropParameters={}, zoomParameters={}):
        textParameters = TextParameters(**textParameters)
        # imageParameters = ImageParameters(**imageParameters)
        shapeParameters = ShapeParameters(**shapeParameters)
        blurParameters = BlurParameters(**blurParameters)
        # cutParameters = CutParameters(**cutParameters)
        # cropParameters = CropParameters(**cropParameters)
        zoomParameters = ZoomParameters(**zoomParameters)

        return cls(
            textParameters=textParameters,
            # imageParameters=imageParameters,
            shapeParameters=shapeParameters,
            blurParameters=blurParameters,
            # cutParameters=cutParameters,
            # cropParameters=cropParameters,
            zoomParameters=zoomParameters,
        )


import pygame as pg
import math
from settings import *
from playstore_maps import *
import cmath
from random import uniform

vec = pg.math.Vector2

pg.init()
screen = pg.display.set_mode((WIDTH, HEIGHT), pg.FULLSCREEN)
clock = pg.time.Clock()
dt = clock.tick(FPS) / 1000

player_img = pg.image.load(PLAYER_IMAGE)

hand_image = pg.image.load(HAND_IMAGE)
width, height = hand_image.get_size()

def draw_text(text, font_name, size, color, x, y, align="nw"):
    font = pg.font.Font(font_name, size)
    text_surface = font.render(text, True, color)
    text_rect = text_surface.get_rect()
    if align == "nw":
        text_rect.topleft = (x, y)
    if align == "ne":
        text_rect.topright = (x, y)
    if align == "sw":
        text_rect.bottomleft = (x, y)
    if align == "se":
        text_rect.bottomright = (x, y)
    if align == "n":
        text_rect.midtop = (x, y)
    if align == "s":
        text_rect.midbottom = (x, y)
    if align == "e":
        text_rect.midright = (x, y)
    if align == "w":
        text_rect.midleft = (x, y)
    if align == "center":
        text_rect.center = (x, y)
    screen.blit(text_surface, text_rect)

# -----------------------------------------------PLAYER--------------------------------------------------------- #
class Player1(pg.sprite.Sprite):
    def __init__(self, x, y):
        self.groups = all_sprites
        pg.sprite.Sprite.__init__(self, self.groups)
        self._layer = PLAYER_LAYER
        self.image = player_img
        self.image.set_colorkey(WHITE)
        self.rect = self.image.get_rect()
        self.rect.center = (int(WIDTH / 2), int(HEIGHT / 2))
        self.pos = vec(x, y)
        self.vel = vec(0, 0)
        self.acc = vec(0, 0)
        self.last_shot = pg.time.get_ticks()
        self.shoot_delay = 250
        self.jumping = True
        print("player1:", self.pos)

    def update(self):
        self.acc = vec(0, GRAVITY)
        keystate = pg.key.get_pressed()
        if keystate[pg.K_a]:
            self.acc.x = -0.5
        if keystate[pg.K_d]:
            self.acc.x = 0.5

        self.acc.x += self.vel.x * FRICTION
        # equations of motion
        self.vel += self.acc
        if abs(self.vel.x) < 0.1:
            self.vel.x = 0
        self.pos += self.vel + 0.5 * self.acc
        # wrap around the sides of the screen
        if self.pos.x > WIDTH:
            self.pos.x = WIDTH
        if self.pos.x < 0:
            self.pos.x = 0

        self.rect.midbottom = self.pos
        self.rect.center = (self.rect.midbottom[0], self.rect.midbottom[1] - 40)

# ----------------------------------------------BULLET---------------------------------------------------------- #
class Bullet(pg.sprite.Sprite):
    def __init__(self, bullet_rotation, bullet_pos, bullet_direction):
        # self._layer = BULLET_LAYER
        self.groups = all_sprites, bullets
        self._layer = BULLET_LAYER
        pg.sprite.Sprite.__init__(self, self.groups)
        self.orig_image = pg.transform.scale(pg.image.load(BULLET_IMAGE), (2, 9))

        self.image = pg.transform.rotate(self.orig_image, bullet_rotation)
        self.rect = self.image.get_rect()
        self.pos = bullet_pos
        self.rect.center = self.pos
        # self.image.set_colorkey(BLACK)
        # spread = uniform(-GUN_SPREAD, GUN_SPREAD)

        # velocity of bullet  = Bullet speed * direction vector
        self.vel = bullet_direction * 200 * 1.1

        # spawn time of bullet after it get deleted
        self.spawn_time = pg.time.get_ticks()

    def update(self):
        self.pos += self.vel * dt
        self.rect.center = self.pos

        # bullet collision with walls
        if pg.sprite.spritecollideany(self, grounds):
            self.kill()

        # bullet deletion
        if pg.time.get_ticks() - self.spawn_time > 5000:
            self.kill()

# ----------------------------------------------PLAYER_HAND----------------------------------------------------- #
class Hand(pg.sprite.Sprite):
    def __init__(self):
        pg.sprite.Sprite.__init__(self)
        self._layer = HAND_LAYER
        self.image = hand_image
        self.rect = self.image.get_rect()
        self.angle = 0
        self.pos = pg.math.Vector2(int(player1.pos[0] + 6), int(player1.pos[1] - 20))
        self.rect.center = (int(WIDTH / 2), int(HEIGHT / 2))
        self.originPos = (width // 2, height // 2)
        self.surf = screen
        self.last_shot = pg.time.get_ticks()
        self.shoot_delay = 250

    def update(self):
        self.pos = pg.math.Vector2(int(player1.pos[0] + 6), int(player1.pos[1] - 20))
        self.rect.center = (player1.rect.center[0] + 3, player1.rect.center[1] + 4)
        # self.blitRotate(screen, self.image, (width // 2, height // 2))
        # calcaulate the axis aligned bounding box of the rotated image
        rel_x = mouse[0] - self.pos[0]
        rel_y = mouse[1] - self.pos[1]
        self.angle = math.atan2(rel_x, rel_y) * 180 // 3.14
        print("angle", self.angle)
        w, h = self.image.get_size()
        box = [pg.math.Vector2(p) for p in [(0, 0), (w, 0), (w, -h), (0, -h)]]
        box_rotate = [p.rotate(self.angle) for p in box]
        min_box = (min(box_rotate, key=lambda p: p[0])[0], min(box_rotate, key=lambda p: p[1])[1])
        max_box = (max(box_rotate, key=lambda p: p[0])[0], max(box_rotate, key=lambda p: p[1])[1])

        # calculate the translation of the pivot
        # pivot        = pg.math.Vector2(originPos[0], -originPos[1])
        # pivot_rotate = pivot.rotate(-angle)
        # pivot_move   = pivot_rotate - pivot

        # calculate the upper left origin of the rotated image
        self.origin = (self.pos[0] - self.originPos[0] + min_box[0], self.pos[1] - self.originPos[1] - max_box[1])
        # origin = pg.math.Vector2(int(mouse[0]), int(mouse[1]))
        # get a rotated image
        self.rotated_image = pg.transform.rotate(self.image, self.angle)
        if pg.time.get_ticks() - self.last_shot > self.shoot_delay:
            self.last_shot = pg.time.get_ticks()
            self.shoot()
        # print("hand_center:", self.pos)

    def shoot(self):
        keys = pg.key.get_pressed()
        bullet_direction = vec(0, 1).rotate(-self.angle)
        if keys[pg.K_f]:
            Bullet(self.angle, self.rect.center, bullet_direction)

    def draw(self, surface):
        # rotate and blit the image
        surface.blit(self.rotated_image, self.origin)

# ----------------------------------------------GROUND---------------------------------------------------------- #
class Ground(pg.sprite.Sprite):
    def __init__(self, x, y, ground_width, ground_height):
        self.groups = all_sprites, grounds
        self._layer = PLATFORM_LAYER
        pg.sprite.Sprite.__init__(self, self.groups)
        # self.image = pg.Surface((width, height))
        # self.image.fill(GREEN)
        # self.rect = self.image.get_rect()
        self.rect = pg.Rect(x, y, ground_width, ground_height)
        self.x = x
        self.y = y
        self.rect.center = self.x, self.y

def draw_grid():
    for x in range(0, WIDTH, TILESIZE):
        pg.draw.line(screen, LIGHTGREY, (x, 0), (x, HEIGHT))
    for y in range(0, HEIGHT, TILESIZE):
        pg.draw.line(screen, LIGHTGREY, (0, y), (WIDTH, y))

def first_interface():
    screen.blit(FIRST_INTERFACE_IMAGE, (0, 0))
    draw_text("WELCOME", GAME_FONT, 50, BLACK, WIDTH / 2, 50, align='center')
    menu_start_button.draw(screen, 45, (0, 0, 0))
    quit_button.draw(screen, 45, (0, 0, 0))
    pg.display.flip()
    # pg.event.wait()

def second_interface():
    screen.blit(SECOND_INTERFACE_IMAGE, (0, 0))
    play_button.draw(screen, 45, (0, 0, 0))
    weapon_button.draw(screen, 45, (0, 0, 0))
    map_settings_button.draw(screen, 45, (0, 0, 0))
    pg.display.flip()

def weapon_interface():
    screen.blit(WEAPON_INTERFACE_IMAGE, (0, 0))
    back_button.draw(screen, 45, (0, 0, 0))
    pg.display.flip()

def escape_interface():
    screen.blit(ESCAPE_INTERFACE_IMAGE, (0, 0))
    continue_button.draw(screen, 45, (0, 0, 0))
    quit_button.draw(screen, 45, (0, 0, 0))
    pg.display.flip()

def map_interface():
    screen.blit(MAP_INTERFACE_IMAGE, (0, 0))
    MAP1_button.draw(screen, 45, (0, 0, 0))
    MAP2_button.draw(screen, 45, (0, 0, 0))
    okay_button.draw(screen, 45, (0, 0, 0))
    pg.display.flip()

# ----------------------------------------------JUMP OF PLAYER-------------------------------------------------- #
def jump():
    hits = pg.sprite.spritecollide(player1, grounds, False)
    if hits:
        player1.vel.y = -20

# -------------------------------------------MAP_SETTINGS------------------------------------------------------ #
map = TiledMap(MAP1)
map_img = map.make_map()
map_rect = map_img.get_rect()

# ----------------------------------------------SPRITES--------------------------------------------------------- #
all_sprites = pg.sprite.LayeredUpdates()
grounds = pg.sprite.Group()
# for ground in GROUND_LIST:
#     Ground(*ground)
for tile_object in map.tmxdata.objects:
    obj_center = vec(tile_object.x + tile_object.width / 2,
                     tile_object.y + tile_object.height / 2)

    if tile_object.name == 'player':
        player1 = Player1(obj_center.x, obj_center.y)
    if tile_object.name == 'ground':
        Ground(obj_center.x, obj_center.y, tile_object.width, tile_object.height)
# player1 = Player1(400, 300)
bullets = pg.sprite.Group()
hand = Hand()

# ------------------------------------------ Camera ----------------------------------------------------------- #
# camera = Camera(map.width, map.height)
# ---------------------------------------- Weapons ------------------------------------------------------------ #

# -----------------------------------------Buttons------------------------------------------------------------- #
menu_start_button = Button(WHITE, WIDTH - 200, HEIGHT - 200, 100, 30, 'Start')
quit_button = Button(WHITE, 100, HEIGHT - 200, 100, 35, 'Quit')
play_button = Button(WHITE, WIDTH - 450, HEIGHT - 100, 100, 30, 'PLAY')
weapon_button = Button(WHITE, 100, HEIGHT - 200, 100, 30, 'WEAPON')
back_button = Button(WHITE, WIDTH - 200, 10, 100, 30, 'BACK')
continue_button = Button(WHITE, 300, 300, 100, 30, 'CONTINUE')
map_settings_button = Button(WHITE, 300, HEIGHT - 200, 100, 30, 'MAPS')
MAP1_button = Button(WHITE, 50, 200, 100, 30, 'MAP_1')
MAP2_button = Button(WHITE, 250, 200, 100, 30, 'MAP_2')
okay_button = Button(WHITE, WIDTH - 100, HEIGHT - 30, 100, 30, 'OKAY')
maps_button = [MAP1_button, MAP2_button]
all_button = [menu_start_button, play_button, quit_button, back_button, weapon_button, continue_button]

# ---------------------------------------------MAIN_GAME_LOOP--------------------------------------------------- #
first_interface_start = True
second_interface_start = True
weapon_interface_start = True
escape_interface_start = True
map_selected = False
last_interface = True
mouse_motion = True
done = False
while not done:
    if first_interface_start:
        first_interface()
    clock.tick(FPS)
    # keep loop running at the right speed

    # global direction
    # Process input (events)
    mouse = pg.mouse.get_pos()
    cursor = pg.mouse.get_pos()

    # print("mouse:", mouse)
    for event in pg.event.get():
        # check for closing window
        if event.type == pg.QUIT:
            pg.quit()
        if not last_interface:
            if event.type == pg.KEYDOWN:
                if event.key == pg.K_ESCAPE:
                    escape_interface_start = True
                    if escape_interface_start:
                        last_interface = True
                        escape_interface()

                if event.key == pg.K_SPACE:
                    jump()
        # -------------------------------------------- Button Working------------------------------------------- #
        if event.type == pg.MOUSEBUTTONDOWN:
            if menu_start_button.isOver(mouse):
                first_interface_start = False
                second_interface()

            if play_button.isOver(mouse):
                last_interface = False

            if weapon_button.isOver(mouse):
                weapon_interface()

            if map_settings_button.isOver(mouse):
                map_interface()

            for selected_map in maps_button:
                if selected_map.isOver(mouse):
                    map_selected = True
                    if selected_map == MAP1_button:
                        map = TiledMap(MAP1)
                        map_img = map.make_map()
                        map_rect = map_img.get_rect()
                        # map.update(MAP1)
                        print('map1')
                    if selected_map == MAP2_button:
                        map = TiledMap(MAP2)
                        map_img = map.make_map()
                        map_rect = map_img.get_rect()
                        # map.update(MAP2)
                        print('map2')
                    print('map is selected')

            if okay_button.isOver(mouse):
                if not map_selected:
                    print('please select at least one map')

                if map_selected:
                    second_interface()

            if back_button.isOver(mouse):
                second_interface()

            if continue_button.isOver(mouse):
                last_interface = False
                escape_interface_start = False

            if quit_button.isOver(mouse):
                pg.quit()
                quit()
        if event.type == pg.MOUSEMOTION:
            for button in all_button:
                if button.isOver(mouse):
                    button.color = GRAY
                else:
                    button.color = WHITE
    # --------------------------------------------- Game starts ----------------------------------------------- #
    if not last_interface:
        screen.fill(WHITE)
        all_sprites.update()
        hand.update()
        if player1.vel.y > 0:
            hits = pg.sprite.spritecollide(player1, grounds, False)
            if hits:
                for hit in hits:
                    # if player1.pos.y - 5 < hit.rect.centery:
                    player1.pos.y = hit.rect.top
                    player1.vel.y = 0

        if player1.rect.top <= HEIGHT / 4:
            player1.pos.y += abs(player1.vel.y)
            for plat in grounds:
                plat.rect.y += abs(player1.vel.y)

        if player1.rect.top >= HEIGHT * 3 / 4:
            player1.pos.y -= abs(player1.vel.y)
            for plat in grounds:
                plat.rect.y -= abs(player1.vel.y)

        # camera.update(player1)
        screen.blit(map_img, map_rect)
        all_sprites.draw(screen)

        # pos = pg.math.Vector2(int(player1.pos[0] + 6), int(player1.pos[1] - 20))
        hand.draw(screen)
        # draw_grid()
        pg.display.flip()

pg.quit()


from django.contrib.auth.models import User
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from app.models import *

def create_category():
    category = Category.objects.create(name='main', slug='main')
    return category

def create_good(category):
    good = Goods.objects.create(
        name='test',
        manufacturer='test_man',
        description='test_desc',
        category=category,
        slug='test_slug',
        price=10
    )
    return good

def create_user(client):
    user = User.objects.create_superuser('admin_user', 'fegesg@test.ru', '123456')
    client.force_authenticate(user=user)
    return user

def create_post(author, category):
    post = Post.objects.create(
        title='test_post',
        text='test_text',
        slug='test_slug',
        author=author,
        category=category
    )
    return post

def create_comment(author, post):
    comment = Comment.objects.create(author=author, text='test_text', post=post)
    return comment

def create_promo():
    promo = PromoCode.objects.create(
        name='test',
        discount_value=5
    )
    return promo

class FavoriteTests(APITestCase):

    def test_create_favorite(self):
        """Добавление в избранное"""
        category = create_category()
        good = create_good(category)
        user = create_user(self.client)
        data = {
            'good': good.id
        }
        request = self.client.post(
            reverse('favorite_create'),
            data,
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_201_CREATED)
        self.assertEqual(FavoriteGood.objects.count(), 1)
        self.assertEqual(FavoriteGood.objects.get().good, good)

    def test_get_favorite(self):
        """Получение избранного"""
        user = create_user(self.client)
        request = self.client.get(
            reverse('favorite_create'),
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_200_OK)

    def test_delete_favorite(self):
        """Удаление из избранного"""
        FavoriteGood.objects.create(good=create_good(create_category()), client_id=create_user(self.client).id)
        good = FavoriteGood.objects.values('good').get()
        request = self.client.delete(
            reverse('favorite_delete', args=[good['good']]),
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(FavoriteGood.objects.count(), 0)

class CategoryTests(APITestCase):
    def test_create_category(self):
        """Создание категории"""
        user = create_user(self.client)
        data = {
            "name": "test_cat",
            "description": "test_desc"}
        request = self.client.post(
            reverse('category_create'),
            data,
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Category.objects.count(), 1)
        self.assertEqual(Category.objects.first().name, 'test_cat')
        request = self.client.get(
            reverse('category_list'),
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_200_OK)
        self.assertEqual(len(request.data), 4)
        category = Category.objects.values('id').first()
        request = self.client.get(
            reverse('category_ops', args=[category['id']]),
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_200_OK)
        self.assertEqual(len(request.data), 5)
        data = {"name": "put_test_cat"}
        request = self.client.put(
            reverse('category_ops', args=[category['id']]),
            data,
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_200_OK)
        self.assertEqual(Category.objects.count(), 1)
        self.assertEqual(Category.objects.first().name, 'put_test_cat')
        data = {"description": "new_test_desc"}
        request = self.client.patch(
            reverse('category_ops', args=[category['id']]),
            data,
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_200_OK)
        self.assertEqual(Category.objects.count(), 1)
        self.assertEqual(Category.objects.first().description, 'new_test_desc')
        request = self.client.delete(
            reverse('category_ops', args=[category['id']]),
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(Category.objects.count(), 0)

class PostsTests(APITestCase):
    def test_posts(self):
        user = create_user(self.client)
        category = create_category()
        data = {
            "title": "test_post",
            "text": "test_text",
            "slug": "test_slug",
            "category": category.id}
        request = self.client.post(
            reverse('post_create'),
            data,
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Post.objects.count(), 1)
        self.assertEqual(Post.objects.first().title, 'test_post')
        request = self.client.get(
            reverse('posts_get')
        )
        self.assertEqual(request.status_code, status.HTTP_200_OK)
        post = Post.objects.values('id').first()
        request = self.client.get(
            reverse('post_edit', args=[post['id']]),
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_200_OK)
        self.assertEqual(len(request.data), 10)
        data = {'text': 'new_test_text'}
        request = self.client.patch(
            reverse('post_edit', args=[post['id']]),
            data,
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_200_OK)
        self.assertEqual(Post.objects.first().text, 'new_test_text')
        data = {
            'title': 'new_test_title',
            "text": "new_test_text",
            "slug": "new_test_slug",
            }
        request = self.client.put(
            reverse('post_edit', args=[post['id']]),
            data,
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_200_OK)
        self.assertEqual(Post.objects.first().title, 'new_test_title')
        request = self.client.delete(
            reverse('post_edit', args=[post['id']]),
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(Post.objects.count(), 0)

class TestGoods(APITestCase):
    def test_goods(self):
        user = create_user(self.client)
        category = create_category()
        data = {
            "name": "test_good_name",
            "manufacturer": "test_man",
            "category": category.id,
            "short_text": "test_short",
            "slug": "test_slug",
            "description": "test_desc"
        }
        request = self.client.post(
            reverse('good_create'),
            data,
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Goods.objects.count(), 1)
        self.assertEqual(Goods.objects.first().slug, 'test_slug')
        request = self.client.get(
            reverse('good_create')
        )
        self.assertEqual(request.status_code, status.HTTP_200_OK)
        request = self.client.get(
            reverse('goods_by_cat', args=[category.id])
        )
        self.assertEqual(request.status_code, status.HTTP_200_OK)
        self.assertEqual(len(request.data), 4)
        good = Goods.objects.values('id').first()
        request = self.client.get(
            reverse('good_edit', args=[good['id']]),
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_200_OK)
        self.assertEqual(len(request.data), 15)
        data = {'name': 'new_test_name'}
        request = self.client.patch(
            reverse('good_edit', args=[good['id']]),
            data,
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_200_OK)
        self.assertEqual(Goods.objects.first().name, 'new_test_name')
        request = self.client.delete(
            reverse('good_edit', args=[good['id']]),
            format='json'
        )
        self.assertEqual(request.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(Goods.objects.count(), 0)

class TestComments(APITestCase):
    def test_create_comment(self):
        """Добавление комментария"""
        user = create_user(self.client)
        post = create_post(user, create_category())
        data = {
            'author': user.id,
            'text': 'test_text',
            'post': post.id
        }
        response = self.client.post(
            reverse('create_comment'),
            data,
            format='json'
        )
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Comment.objects.count(), 1)
        self.assertEqual(Comment.objects.first().post, post)

    def test_get_comment(self):
        """Получение комментария"""
        response = self.client.get(reverse('create_comment'), format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_edit_comment(self):
        """Редактирование комментария"""
        data = {'text': 'new_test_text'}
        user = create_user(self.client)
        comment = create_comment(author=user, post=create_post(author=user, category=create_category()))
        response = self.client.patch(
            reverse('comment_ops', args=[comment.id]),
            data,
            format='json'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(Comment.objects.first().text, 'new_test_text')

    def test_delete_comment(self):
        """Удаление комментария"""
        user = create_user(self.client)
        comment = create_comment(author=user, post=create_post(author=user, category=create_category()))
        response = self.client.delete(
            reverse('comment_ops', args=[comment.id]),
            format='json'
        )
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(Comment.objects.count(), 0)

    def test_create_subcomment(self):
        """Добавление дочернего комментария"""
        user = create_user(self.client)
        data = {'text': 'subcomment_text', 'author': user.id}
        comment = create_comment(author=user, post=create_post(author=user, category=create_category()))
        response = self.client.post(
            reverse('create_subcomment', args=[comment.id]),
            data,
            format='json'
        )
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Comment.objects.count(), 2)
        self.assertEqual(comment.child_comment.count(), 1)

class CartTest(APITestCase):
    def test_add_to_cart(self):
        """Добавление в корзину"""
        user = create_user(self.client)
        category = create_category()
        good = create_good(category)
        data = {
            'quantity': 2,
            'good': good.id
        }
        response = self.client.post(
            reverse('to-cart'),
            data,
            format='json'
        )
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(GoodsInCart.objects.count(), 1)
        self.assertEqual(Cart.objects.get(customer=user).amount_items, 20)
        self.assertEqual(Cart.objects.get(customer=user).promo_price, None)
        """Промо код"""
        promo = create_promo()
        data = {'promo_code': 'test'}
        response = self.client.post(
            reverse('promo'),
            data,
            format='json'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(Cart.objects.get(customer=user).promo_price, 15)

    def get_cart(self):
        """Получение элементов корзины"""
        user = create_user(self.client)
        response = self.client.get(
            reverse('to-cart'),
            format='json'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def edit_cart(self):
        """Изменение количества товара в корзине"""
        user = create_user(self.client)
        category = create_category()
        good = create_good(category)
        good_cart = GoodsInCart.objects.create(good=good, cart__customer=user, quantity=1)
        data = {'quantity': 2}
        response = self.client.put(
            reverse('cart-edit', args=[good.id]),
            data,
            format='json'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(good_cart.quantity, 2)

    def delete_carts_good(self):
        """Удаление товара из корзины"""
        user = create_user(self.client)
        category = create_category()
        good = create_good(category)
        GoodsInCart.objects.create(good=good, cart__customer=user, quantity=1)
        response = self.client.delete(
            reverse('cart-edit', args=[good.id]),
            format='json'
        )
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(GoodsInCart.objects.count(), 0)

class OrderTest(APITestCase):
    def test_order(self):
        """Создание заказа и получение в истории"""
        user = create_user(self.client)
        category = create_category()
        good = create_good(category)
        promo = create_promo()
        cart = Cart.objects.get(customer=user, accepted=False)
        GoodsInCart.objects.create(good=good, cart=cart, quantity=1)
        cart.promo_code = promo
        cart.save()
        data = {
            #'comment': 'test_comment',
            'delivery_address': 'test_address',
            'receiver_name': 'test_name'
        }
        response = self.client.post(
            reverse('add_order'),
            data,
            format='json'
        )
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Order.objects.count(), 1)
        #self.assertEqual(Order.objects.first().comment, 'test_comment')
        self.assertEqual(Order.objects.first().amount, 5)
        """Проверка в истории заказов"""
        response = self.client.get(
            reverse('order_history'),
            format='json'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 4)
        """Проверка состава заказа в истории"""
        order = Order.objects.first()
        response = self.client.get(
            reverse('order_list', args=[order.id]),
            format='json'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 4)


from .sup_gan import SupGanTrainer
from abc import abstractmethod
import torch

class Pix2pixGanTrainer(SupGanTrainer):
    d_turn = 1

    def __init__(self, logdir, nepochs, gpu_ids_abs, netG, netD, optG, optD, datasets):
        """ A pixel to pixel gan trainer

        :param logdir:Path of log
        :param nepochs:Amount of epochs.
        :param gpu_ids_abs: he id of gpus which t obe used. If use CPU, set ``[]``.
        :param netG:Generator model.
        :param netD:Discrimiator model
        :param optG:Optimizer of Generator.
        :param optD:Optimizer of Discrimiator.
        :param datasets:Datasets.
        """
        super(Pix2pixGanTrainer, self).__init__(logdir, nepochs, gpu_ids_abs, netG, netD, optG, optD, datasets)

    def get_data_from_batch(self, batch_data: list, device: torch.device):
        input_tensor, ground_truth_tensor = batch_data[0], batch_data[1]
        return input_tensor, ground_truth_tensor

    def _watch_images(self, tag, grid_size=(3, 3), shuffle=False, save_file=True):
        self.watcher.image(self.input,
                           self.current_epoch,
                           tag="%s/input" % tag,
                           grid_size=grid_size,
                           shuffle=shuffle,
                           save_file=save_file)
        self.watcher.image(self.fake,
                           self.current_epoch,
                           tag="%s/fake" % tag,
                           grid_size=grid_size,
                           shuffle=shuffle,
                           save_file=save_file)
        self.watcher.image(self.ground_truth,
                           self.current_epoch,
                           tag="%s/real" % tag,
                           grid_size=grid_size,
                           shuffle=shuffle,
                           save_file=save_file)

    @abstractmethod
    def compute_d_loss(self):
        """ Rewrite this method to compute your own loss Discriminator.

        You should return a **loss** for the first position.
        You can return a ``dict`` of loss that you want to visualize on the second position.like
        The training logic is :
            self.input, self.ground_truth = self.get_data_from_batch(batch, self.device)
            self.fake = self.netG(self.input)
            self._train_iteration(self.optD, self.compute_d_loss, csv_filename="Train_D")
            if (self.step % self.d_turn) == 0:
                self._train_iteration(self.optG, self.compute_g_loss, csv_filename="Train_G")
        So, you use `self.input` , `self.ground_truth`, `self.fake`, `self.netG`, `self.optD` to compute loss.
        Example::

            d_fake = self.netD(self.fake.detach())
            d_real = self.netD(self.ground_truth)
            var_dic = {}
            var_dic["LS_LOSSD"] = loss_d = 0.5 * (torch.mean((d_real - 1) ** 2) + torch.mean(d_fake ** 2))
            return loss_d, var_dic

        """
        loss_d = None
        var_dic = {}

        return loss_d, var_dic

    @abstractmethod
    def compute_g_loss(self):
        """Rewrite this method to compute your own loss of Generator.

        You should return a **loss** for the first position.
        You can return a ``dict`` of loss that you want to visualize on the second position.like
        The training logic is :
            self.input, self.ground_truth = self.get_data_from_batch(batch, self.device)
            self.fake = self.netG(self.input)
            self._train_iteration(self.optD, self.compute_d_loss, csv_filename="Train_D")
            if (self.step % self.d_turn) == 0:
                self._train_iteration(self.optG, self.compute_g_loss, csv_filename="Train_G")
        So, you use `self.input` , `self.ground_truth`, `self.fake`, `self.netG`, `self.optD` to compute loss.
        Example::

            d_fake = self.netD(self.fake, self.input)
            var_dic = {}
            var_dic["LS_LOSSG"] = loss_g = 0.5 * torch.mean((d_fake - 1) ** 2)
            return loss_g, var_dic

        """
        loss_g = None
        var_dic = {}
        return loss_g, var_dic

    @abstractmethod
    def compute_valid(self):
        """Rewrite this method to compute valid_epoch values.

        You can return a ``dict`` of values that you want to visualize.

        .. note::

            This method is under ``torch.no_grad():``. So, it will never compute grad.
            If you want to compute grad, please use ``torch.enable_grad():`` to wrap your operations.

        Example::

            d_fake = self.netD(self.fake.detach())
            d_real = self.netD(self.ground_truth)
            var_dic = {}
            var_dic["WD"] = w_distance = (d_real.mean() - d_fake.mean()).detach()
            return var_dic

        """
        _, d_var_dic = self.compute_g_loss()
        _, g_var_dic = self.compute_d_loss()
        var_dic = dict(d_var_dic, **g_var_dic)
        return var_dic

    def valid_epoch(self):
        super(Pix2pixGanTrainer, self).valid_epoch()
        self.netG.eval()
        self.netD.eval()
        if self.fixed_input is None:
            for batch in self.datasets.loader_test:
                if isinstance(batch, (list, tuple)):
                    self.fixed_input, fixed_ground_truth = self.get_data_from_batch(batch, self.device)
                    self.watcher.image(fixed_ground_truth, self.current_epoch, tag="Fixed/groundtruth",
                                       grid_size=(6, 6),
                                       shuffle=False)
                else:
                    self.fixed_input = batch.to(self.device)
                self.watcher.image(self.fixed_input, self.current_epoch, tag="Fixed/input",
                                   grid_size=(6, 6),
                                   shuffle=False)
                break

        # watching the variation during training by a fixed input
        with torch.no_grad():
            fake = self.netG(self.fixed_input).detach()
        self.watcher.image(fake, self.current_epoch, tag="Fixed/fake", grid_size=(6, 6), shuffle=False)

        # saving training processes to build a .gif.
        self.watcher.set_training_progress_images(fake, grid_size=(6, 6))

        self.netG.train()
        self.netD.train()

    def test(self):
        """ Test your model when you finish all epochs.

        This method will call when all epochs finish.

        Example::

            for index, batch in enumerate(self.datasets.loader_test, 1):
                # For test only have input without groundtruth
                input = batch.to(self.device)
                self.netG.eval()
                with torch.no_grad():
                    fake = self.netG(input)
                self.watcher.image(fake, self.current_epoch, tag="Test/fake", grid_size=(4, 4), shuffle=False)
            self.netG.train()
        """
        for batch in self.datasets.loader_test:
            self.input, _ = self.get_data_from_batch(batch, self.device)
            self.netG.eval()
            with torch.no_grad():
                fake = self.netG(self.input).detach()
            self.watcher.image(fake, self.current_epoch, tag="Test/fake", grid_size=(7, 7), shuffle=False)
        self.netG.train()


# NOTE 1
# If your power supply goes into an error state (i.e., the word
# error is printed on the front of the device), use this command
# power_supply.write("*CLS")
# to clear the error so that you can rerun your code. The supply
# typically beeps after an error has occured.

import visa
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import time
import statistics
mpl.style.use('ggplot')

#%%
# This section of the code cycles through all USB connected devices to the computer.
# The code figures out the USB port number for each instrument.
# The port number for each instrument is stored in a variable named “instrument_id”
# If the instrument is turned off or if you are trying to connect to the
# keyboard or mouse, you will get a message that you cannot connect on that port.
device_manager = visa.ResourceManager()
devices = device_manager.list_resources()
number_of_device = len(devices)

power_supply_id = -1
# waveform_generator_id = -1
# digital_multimeter_id = -1
# oscilloscope_id = -1

# assumes only the DC power supply is connected
for i in range (0, number_of_device):

# check that it is actually the power supply
    try:
        device_temp = device_manager.open_resource(devices[i])
        print("Instrument connect on USB port number [" + str(i) + "] is " + device_temp.query("*IDN?"))
        if (device_temp.query("*IDN?") == 'HEWLETT-PACKARD,E3631A,0,3.0-6.0-2.0\r\n'):
            power_supply_id = i
        # if 'Agilent Technologies,33511B' in device_temp.query("*IDN?"):
        #     waveform_generator_id = i
        # if 'Agilent Technologies,34461A' in device_temp.query("*IDN?"): # == 'Agilent Technologies,34461A,MY53207926,A.01.10-02.25-01.10-00.35-01-01\n'):
        #     digital_multimeter_id = i
        # if 'Keysight Technologies,34461A' in device_temp.query("*IDN?"): #,MY53212931,A.02.08-02.37-02.08-00.49-01-01\n'):
        #     digital_multimeter_id = i
        # if 'KEYSIGHT TECHNOLOGIES,MSO-X 3024T' in device_temp.query("*IDN?"): # == 'KEYSIGHT TECHNOLOGIES,MSO-X 3024T,MY54440281,07.10.2017042905\n'):
        #     oscilloscope_id = i
        device_temp.close()
    except:
        print("Instrument on USB port number [" + str(i) + "] cannot be connected. The instrument might be powered of or you are trying to connect to a mouse or keyboard.\n")

#%%
# Open the USB communication port with the power supply.
# The power supply is connected on USB port number power_supply_id.
# If the power supply ss not connected or turned off, the program will exit.
# Otherwise, the power_supply variable is the handler to the power supply

if (power_supply_id == -1):
    print("Power supply instrument is not powered on or connected to the PC.")
else:
    print("Power supply is connected to the PC.")
    power_supply = device_manager.open_resource(devices[power_supply_id])

# if (digital_multimeter_id == -1):
#     print("Multimeter instrument is not powered on or connected to the PC.")
# else:
#     print("Multimeter is connected to the PC.")
#     digital_multimeter = device_manager.open_resource(devices[digital_multimeter_id])

# if (oscilloscope_id == -1):
#     print("Oscilloscope instrument is not powered on or connected to the PC.")
# else:
#     print("Oscilloscope is connected to the PC.")
#     oscilloscope = device_manager.open_resource(devices[oscilloscope_id])

#%%
# The power supply output voltage will be swept from 0 to 8V in steps of 0.1V.
# This voltage will be applied on the 6V output ports.
# For each voltage applied on the 6V power supply, we will measure the actual
# voltage and current supplied by the power supply.
# If your circuit operates correctly, the applied and measured voltage will be the same.
# If the power supply reaches its maximum allowed current,
# then the applied voltage will not be the same as the measured voltage.

    ### Positive Terminal on left (black)
    Resistor = 47                       # ohms
    max_P = .5                          # W
    max_v_i = np.sqrt(max_P * Resistor) #V

    print("The max voltage calculated from max power and resistor value is {}".format(max_v_i))

    max_v = max_v_i

    # print("The voltage we will use is 90% of the max voltage rating, {}".format(max_v))

    num_measurements = 50               # number of measurements
    num_mini_measurements = 100          # number of measurements within measurement (v, I)
    output_voltage = np.linspace(0, max_v, num_measurements)

    measured_voltage = np.empty((num_measurements, num_mini_measurements)) #np.array([]) # create an empty list to hold our values
    measured_current = np.empty((num_measurements, num_mini_measurements)) #np.array([]) # create an empty list to hold our values

    I_SD = np.empty((num_measurements))
    I_mean = np.empty((num_measurements))

    V_SD = np.empty((num_measurements))
    V_mean = np.empty((num_measurements))

    print(power_supply.write("OUTPUT ON")) # power supply output is turned on

    # loop through the different voltages we will apply to the power supply
    # For each voltage applied on the power supply,
    # measure the voltage and current supplied by the 6V power supply
    for i, v in enumerate(output_voltage):
        # apply the desired voltage on teh 6V power supply and limist the output current to 60mA
        if v > max_v_i+.1:
            print("Maximum output resistor voltage exceeded. Turning off power supply to preserve circuit")
            break
        print(v)
        power_supply.write("APPLy P25V, %0.2f, 0.11" % v) #max_I = 0.103A

        for j in range(0, num_mini_measurements):

            # pause 10ms to let things settle
            time.sleep(0.5) # min 240ms

            # read the output voltage on the 25V power supply
            measured_voltage_tmp = power_supply.query("MEASure:VOLTage:DC? P25V")
            measured_voltage[i][j] = float(measured_voltage_tmp)

            # read the output current on the 25V power supply
            measured_current_tmp = power_supply.query("MEASure:CURRent:DC? P25V")
            measured_current[i][j] = float(measured_current_tmp)

        I_mean[i] = statistics.mean(measured_current[i])
        I_SD[i] = statistics.stdev(measured_current[i])

        V_mean[i] = statistics.mean(measured_voltage[i])
        V_SD[i] = statistics.stdev(measured_voltage[i])

    # power supply output is turned off
    print(power_supply.write("OUTPUT OFF"))
    print("Power supply off")

    # close the power supply USB handler. Otherwise you cannot connect to it in the future
    power_supply.close()

#%%
    plt.figure()
    plt.plot(output_voltage,I_mean)
    plt.title("Applied Volts vs. Measured Current Mean")
    plt.xlabel("Applied Volts [V]")
    plt.ylabel("Measured Current Mean [A]")
    plt.draw()

    plt.figure()
    plt.plot(output_voltage,I_SD)
    plt.title("Applied Volts vs. Measured Current Standard Deviation")
    plt.xlabel("Applied Volts [V]")
    plt.ylabel("Current Standard Deviation [A]")
    plt.draw()

    plt.figure()
    plt.plot(output_voltage,V_mean)
    plt.title("Applied Volts vs. Measured Voltage Mean")
    plt.xlabel("Applied Volts [V]")
    plt.ylabel("Voltage Mean [V]")
    plt.draw()

    plt.figure()
    plt.plot(output_voltage,V_SD)
    plt.title("Applied Volts vs. Measured VOltage Standard Deviation")
    plt.xlabel("Applied Volts [V]")
    plt.ylabel("Voltage Standard Deviation [V]")
    plt.draw()

    plt.figure()
    plt.plot(output_voltage,I_mean * V_mean)
    plt.title("Applied Volts vs. Measured Power (From I and Voltage Mean)")
    plt.xlabel("Applied Volts [V]")
    plt.ylabel("Power [W]")
    plt.draw()

    # show all plots
    plt.show()

#%%

    power_SD = np.empty((num_measurements))
    power_mean = np.empty((num_measurements))

    for i, v in enumerate(output_voltage):
        for j in range(0, num_mini_measurements):
            power_mean[i] = statistics.mean((measured_current[i])*measured_voltage[i])
            power_SD[i] = statistics.stdev((measured_current[i])*measured_voltage[i])

    plt.figure()
    plt.plot(output_voltage,power_SD)
    plt.title("Applied Volts vs. Power Standard Deviation")
    plt.xlabel("Applied Volts [V]")
    plt.ylabel("Power Standard Deviation [W]")
    plt.draw()

    plt.figure()
    plt.plot(output_voltage,power_mean)
    plt.title("Applied Volts vs. Power Mean")
    plt.xlabel("Applied Volts [V]")
    plt.ylabel("Power Mean [W]")
    plt.draw()

    # show all plots
    plt.show()


import boto3
import json
import os
import logging
from datetime import datetime
from pytz import timezone

from datadog_api_client import ApiClient, Configuration
from datadog_api_client.v2.api.logs_api import LogsApi
from datadog_api_client.v2.model.content_encoding import ContentEncoding
from datadog_api_client.v2.model.http_log import HTTPLog
from datadog_api_client.v2.model.http_log_item import HTTPLogItem

ENV = os.environ.get("ENV", "")
SERVICE = os.environ.get("SERVICE", "watts")
SOURCE = os.environ.get("SOURCE", "watts-ifttt")
VERSION = os.environ.get("VERSION", "")
DD_API_KEY_PARAM = os.environ.get("DD_API_KEY_PARAM", "DDApiKey")

if ENV == "staging":
    logging.getLogger().setLevel(logging.DEBUG)
else:
    logging.getLogger().setLevel(logging.INFO)

def timestamp_conversion(createdAt):
    # Convert 'CreatedAt' datetime provided by IFTTT to ISO 8601
    d = datetime.strptime(createdAt, "%B %d, %Y at %I:%M%p")
    ny_time = timezone('America/New_York').localize(d)
    utc_time = ny_time.astimezone(timezone('UTC'))
    return utc_time.strftime("%Y-%m-%dT%H:%M:%S%z")

def get_param(name):
    # Get an SSM parameter by name
    logging.debug("Fetching SSM parameter")
    ssm = boto3.client('ssm')
    parameter = ssm.get_parameter(Name=name, WithDecryption=True)
    return parameter['Parameter']['Value']

def send_dd_log(payload):
    logging.debug("Logging data: " + str(payload))
    body = HTTPLog(
        [
            HTTPLogItem(
                ddsource=SOURCE,
                ddtags=f"env:{ENV},version:{VERSION}",
                message=json.dumps(payload),
                service=SERVICE,
            ),
        ]
    )

    configuration = Configuration()
    configuration.api_key["apiKeyAuth"] = get_param(DD_API_KEY_PARAM)
    with ApiClient(configuration) as api_client:
        api_instance = LogsApi(api_client)
        response = api_instance.submit_log(content_encoding=ContentEncoding.DEFLATE, body=body)
        print(response)

def lambda_handler(event, context):
    try:
        body = json.loads(event["body"])
        if "CreatedAt" not in body.keys() and "date" not in body.keys():
            logging.error("Timestamp not in request body")
            raise KeyError
    except Exception as e:
        logging.error("Failed to load request body")
        logging.debug(e)
        logging.debug(event["body"])
        return {
            "statusCode": 400,
            "body": json.dumps({
                "message": "oopsies. please include a legit body"
            })
        }

    if "timestamp" not in body.keys():
        # Convert IFTTT time to a format Datadog accepts
        timestamp = body.get("CreatedAt", body.get("date"))
        body["timestamp"] = timestamp_conversion(timestamp)

    logging.info("Logging ride created at " + str(body["timestamp"]))
    send_dd_log(body)
    logging.info("Done")

    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "uploaded"
        }),
    }


import numpy as np
import pandas as pd
import os

import cv2

import tensorflow as tf
import tensorflow.python.util.deprecation as deprecation
deprecation._PRINT_DEPRECATION_WARNINGS = False

import keras.backend as K
from keras.models import Model
from keras.layers import Input
from keras.layers import Dense, Flatten, BatchNormalization, Dropout
from keras.layers import Conv2D, MaxPooling2D
from keras.models import model_from_yaml

from keras.models import load_model

class IdentifyFace():
	def __init__(self, weight_path=['face_detector/weights/gender-ethnicity.hdf5',
									'face_detector/weights/emotion.hdf5',
									'face_detector/weights/age.hdf5']):

		self._ge_weight_path = weight_path[0]
		self._e_weight_path = weight_path[1]
		self._a_weight_path = weight_path[2]

		self.__ge_model = None
		self.__e_model = None
		self.__a_model = None

		self.__graph1 = None
		self.__graph2 = None
		self.__graph3 = None
		self.__session1 = None
		self.__session2 = None
		self.__session3 = None

		print("[INFO] Preparing Model and loading weights...")
		self.ge_buildModel()
		self.e_buildModel()
		self.a_buildModel()
		print("[INFO] Done")

	# Model for Gender and Ethnicity
	def ge_buildModel(self):
		self.__graph1 = tf.Graph()
		with self.__graph1.as_default():
			self.__session1 = tf.Session()
			with self.__session1.as_default():
				yaml_file = open('face_detector/weights/model-gender-ethnicity.yaml', 'r')
				loaded_model_yaml = yaml_file.read()
				yaml_file.close()
				loaded_model = model_from_yaml(loaded_model_yaml)
				# load weights into new model
				loaded_model.load_weights(self._ge_weight_path)
				self.__ge_model = loaded_model

	# Model for age
	def a_buildModel(self):
		self.__graph3 = tf.Graph()
		with self.__graph3.as_default():
			self.__session3 = tf.Session()
			with self.__session3.as_default():
				age_file = open('face_detector/weights/model-age.yaml', 'r')
				age_model_yaml = age_file.read()
				age_file.close()
				age_model = model_from_yaml(age_model_yaml)
				# load weights into new model
				age_model.load_weights(self._a_weight_path)
				self.__a_model = age_model

	# Model for emotion
	def e_buildModel(self):
		self.__graph2 = tf.Graph()
		with self.__graph2.as_default():
			self.__session2 = tf.Session()
			with self.__session2.as_default():
				inputs = Input(shape=(48,48,1))
				emotion = self.__emotion_classification(inputs)
				e_model = Model(inputs=inputs, outputs=emotion)
				e_model = load_model(self._e_weight_path)
				self.__e_model = e_model

	# Prediction from all three classifiers.
	def predict(self, image_dict):
		print("[INFO] Predicting Gender, Ethnicity, Age and Emotion...")
		output = {}
		for face_id, image in image_dict.items():

			gra_image = cv2.resize(image, (200,200))

			e_image = cv2.resize(image, (48,48))
			e_image = cv2.cv2.cvtColor(e_image, cv2.COLOR_RGB2GRAY)

			gra_image = gra_image.reshape(((1,)+gra_image.shape))
			e_image = e_image.reshape((1,48,48,1))

			with self.__graph1.as_default():
				with self.__session1.as_default():
					gender_ethnicity = self.__ge_model.predict(gra_image)
					# print("[CHECKING] Gender :", gender_ethnicity)
					# print("[CHECKING] Gender:", np.argmax(gender_ethnicity))

					gender, ethnicity = self.__decodeGenderEthnicity(np.argmax(gender_ethnicity))

			with self.__graph2.as_default():
				with self.__session2.as_default():
					emotion = self.__e_model.predict(e_image)

					emotion = self.__decodeEmotion(np.argmax(emotion))

			with self.__graph3.as_default():
				with self.__session3.as_default():
					age_prediction = self.__a_model.predict(gra_image)
					# print("[CHECKING] Age:", age_prediction)
					# print("[CHECKING] Age:", np.argmax(age_prediction))
					age = self.__degroupAge(np.argmax(age_prediction))

			output[face_id] = [gender, ethnicity, age, emotion]

		print("[INFO] Done")
		return output

	# Decode prediction for Gender and Ethnicity
	def __decodeGenderEthnicity(self, gender_ethnicity):
		if gender_ethnicity==0:
		    return self.__decodeGender(0), self.__decodeEthnicity(0)
		elif gender_ethnicity==1:
			return self.__decodeGender(0), self.__decodeEthnicity(1)
		elif gender_ethnicity==2:
			return self.__decodeGender(0), self.__decodeEthnicity(2)
		elif gender_ethnicity==3:
			return self.__decodeGender(0), self.__decodeEthnicity(3)
		elif gender_ethnicity==4:
			return self.__decodeGender(0), self.__decodeEthnicity(4)
		elif gender_ethnicity==5:
			return self.__decodeGender(1), self.__decodeEthnicity(0)
		elif gender_ethnicity==6:
			return self.__decodeGender(1), self.__decodeEthnicity(1)
		elif gender_ethnicity==7:
			return self.__decodeGender(1), self.__decodeEthnicity(2)
		elif gender_ethnicity==8:
			return self.__decodeGender(1), self.__decodeEthnicity(3)
		else:
			return self.__decodeGender(1), self.__decodeEthnicity(4)

	# Label Gender's prediction
	def __decodeGender(self, gender):
		if gender==0:
			return 'male'
		else:
			return 'female'

	# Label Ethnicity's prediction
	def __decodeEthnicity(self, ethnicity):
		if ethnicity==0:
			return 'white'
		elif ethnicity==1:
			return 'black'
		elif ethnicity==2:
			return 'asian'
		elif ethnicity==3:
			return 'indian'
		elif ethnicity==4:
			return 'haspanic or arabic'

	# Label Age's prediction
	def __degroupAge(self, age):
		# Age_below20
		if age==0 or age==1:
			return 'age_below20'

		# Age_20_30
		elif age==3 or age==3 or age==4:
			return 'age_20_30'

		# Age_30_40
		elif age==5 or age==6 or age==7 or age==8:
			return 'age_30_40'

		# Age_40_50
		elif age==8 or age==9:
			return 'age_40_50'

		# Age_above_50
		else:
			return 'age_above_50'

	# Label Emotion's prediction
	def __decodeEmotion(self, emotion):

		if emotion==0:
			return 'Angry'
		elif emotion==1:
			return 'Happy'
		elif emotion==2:
			return 'Sad'
		else:
			return 'Neutral'

	# Build model for emotion classification.

	###
	#ToDo: Remove this and use .yaml file format for model.
	###
	def __emotion_classification(self, inputs):
	    x = Conv2D(32, (3, 3), padding="same", activation='relu')(inputs)
	    x = Conv2D(32, (3, 3), padding="same", activation='relu')(x)
	    x = MaxPooling2D(pool_size=(2, 2))(x)
	    x = Dropout(0.5)(x)

	    x = Conv2D(64, (3, 3), padding="same", activation='relu')(x)
	    x = Conv2D(64, (3, 3), padding="valid", activation='relu')(x)
	    x = MaxPooling2D(pool_size=(2, 2))(x)
	    x = Dropout(0.5)(x)

	    x = Conv2D(96, (3, 3), padding="same", activation='relu')(x)
	    x = Conv2D(96, (3, 3), padding="valid", activation='relu')(x)
	    x = MaxPooling2D(pool_size=(2, 2))(x)
	    x = Dropout(0.5)(x)

	    x = Conv2D(128, (3, 3), dilation_rate=(2, 2), padding="same", activation='relu')(x)
	    x = Conv2D(128, (3, 3), padding="valid", activation='relu')(x)
	    x = MaxPooling2D(pool_size=(2, 2))(x)
	    x = Dropout(0.5)(x)

	    x = Flatten()(x)
	    x = Dense(512, activation='relu')(x)
	    x = Dense(128, activation='relu')(x)
	    x = Dense(4 , activation='softmax')(x)

	    model = Model(inputs=inputs, outputs=x)

	    return x


import re
import json
import openai
from time import time,sleep

def open_file(filepath):
    with open(filepath, 'r', encoding='utf-8') as infile:
        return infile.read()

def save_file(filepath, content):
    with open(filepath, 'w', encoding='utf-8') as outfile:
        outfile.write(content)

def load_info():
    info = open_file('my_info.json')
    info = json.loads(info)
    return info

openai.api_key = open_file('openaiapikey.txt')  # update this - create the file if needed

def gpt3_completion(prompt, engine='text-davinci-002', temp=0.7, top_p=1.0, tokens=1000, freq_pen=0.0, pres_pen=0.0, stop=['asdfasdf', 'asdasdf']):
    max_retry = 5
    retry = 0
    prompt = prompt.encode(encoding='ASCII',errors='ignore').decode()  # force it to fix any unicode errors
    while True:
        try:
            response = openai.Completion.create(
                engine=engine,
                prompt=prompt,
                temperature=temp,
                max_tokens=tokens,
                top_p=top_p,
                frequency_penalty=freq_pen,
                presence_penalty=pres_pen,
                stop=stop)
            text = response['choices'][0]['text'].strip()
            #text = re.sub('\s+', ' ', text)
            filename = '%s_gpt3.txt' % time()
            save_file('gpt3_logs/%s' % filename, prompt + '\n\n==========\n\n' + text)
            return text
        except Exception as oops:
            retry += 1
            if retry >= max_retry:
                return "GPT3 error: %s" % oops
            print('Error communicating with OpenAI:', oops)
            sleep(1)

if __name__ == '__main__':
    info = load_info()
    #print(info)
    text_block = ''
    for i in info:
        text_block += '%s: %s\n' % (i['label'], i['answer'])
    #print(text_block)
    prompt = open_file('prompt_cover_letter.txt').replace('<<INFO>>', text_block)
    #print(prompt)
    completion = gpt3_completion(prompt)
    print('\n\nCOVER LETTER:', completion)
    save_file('cover_letter_%s.txt' % time(), completion)
    ### get professional objective
    prompt = open_file('prompt_professional_objective.txt').replace('<<INFO>>', text_block)
    #print(prompt)
    completion = gpt3_completion(prompt)
    print('\n\nPROFESSIONAL OBJECTIVE:', completion)
    save_file('professional_objective_%s.txt' % time(), completion)