# 행렬의 세로 길이(행 개수) rows, 가로 길이(열 개수) columns, 그리고 회전들의 목록 queries가 주어질 때,
# 각 회전들을 배열에 적용한 뒤,
# 그 회전에 의해 위치가 바뀐 숫자들 중 가장 작은 숫자들을 순서대로 배열에 담아 return 하도록 solution 함수를 완성해주세요.
from collections import deque

def solution(rows, columns, queries):
    answer = []
    matrix = []
    queries = deque(queries)
    for i in range(rows):
        lst = []
        for j in range(1,columns+1):
            lst.append(rows*i+j)
        matrix.append(lst)
    while queries:
        lst = deque()
        x1,y1,x2,y2 = queries.popleft()
        print("lst, (x1,y1,x2,y2) :  ", lst, (x1,y1,x2,y2))
        for a in range(y1,y2):
            lst.append(matrix[x1-1][a-1])
        for b in range(x1,x2):
            lst.append(matrix[b-1][y2-1])
        for c in range(y2,y1,-1):
            lst.append(matrix[x2-1][c-1])
        for d in range(x2,x1,-1):
            lst.append(matrix[d-1][y1-1])
        lst.rotate(1)
        answer.append(min(lst))
        for a in range(y1,y2):
            matrix[x1-1][a-1] = lst.popleft()
        for b in range(x1,x2):
            matrix[b-1][y2-1] = lst.popleft()
        for c in range(y2,y1,-1):
            matrix[x2-1][c-1] = lst.popleft()
        for d in range(x2,x1,-1):
            matrix[d-1][y1-1] = lst.popleft()
    return answer

'''
rows = 6
columns = 6
queries = [[2,2,5,4],[3,3,6,6],[5,1,6,3]]
# result = [8, 10, 25]
print(solution(rows,columns,queries))
'''

rows = 3
columns = 3

queries = [[1,1,2,2],[1,2,2,3],[2,1,3,2],[2,2,3,3]]
# result  = [1, 1, 5, 3]
print(solution(rows,columns,queries))

'''
rows = 100
columns = 97
queries = [[1,1,100,97]]
# return [1]
'''


from typing import List

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:

        if len(matrix) == 0:
            return []

        res = []
        top = 0
        right = len(matrix[0]) - 1
        bottom = len(matrix) - 1
        left = 0
        direction = 'right'

        while top <= bottom and left <= right:
            if direction == 'right':
                for i in range(left, right + 1):
                    res.append(matrix[top][i])
                top += 1
                direction = 'bottom'

            elif direction == 'bottom':
                for i in range(top, bottom + 1):
                    res.append(matrix[i][right])
                right -= 1
                direction = 'left'

            elif direction == 'left':
                for i in range(right, left - 1, -1):
                    res.append(matrix[bottom][i])
                bottom -= 1
                direction = 'top'

            elif direction == 'top':
                for i in range(bottom, top - 1, -1):
                    res.append(matrix[i][left])
                left += 1
                direction = 'right'
        return res

if __name__ == '__main__':
    mat = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
    p = Solution()
    print(p.spiralOrder(mat))


from django.db import models
from django.conf import settings
from candidate.models import CandidateProfile
from datetime import date
# Create your models here.

class RecruiterProfile(models.Model):
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
    name = models.CharField('Name', max_length=200)
    zip_code = models.IntegerField('Zip Code')
    company = models.CharField('Company', max_length=200)

    def __str__(self):
        return f"{self.user.username}"

class JobPost(models.Model):

    recruiter = models.ForeignKey(RecruiterProfile, on_delete=models.CASCADE)
    pos_title = models.CharField("Position Title", max_length=200)
    type = models.CharField("Type", max_length=200)
    location = models.CharField("Location", max_length=200)
    des_skills = models.TextField("Desired Skills")
    description = models.TextField("Description")
    company = models.CharField("Company", max_length=200)
    exp_date = models.DateField("Expiration Date")
    status = models.CharField("Status", max_length=200)
    interested_candidates = models.PositiveIntegerField(
        "Interested Candidates", default=0)
    interested_ids = models.TextField("Interested IDs", default="")

    def __str__(self):
        return f"{self.pos_title} ({self.type}) - {self.company}"

    def expire(self):
        if date.today() > self.exp_date:
            self.status = "Inactive"
            self.save()
        return True

    def listify(self):
        # get candidates
        candidates = CandidateProfile.objects.get_queryset()
        # add compat scores
        for c in candidates:
            c.compatability_score = calculateCompatScore(c, self)
            c.save()
        # sort them by sorting algorithm
        #candidates = sorted(candidates, key=lambda x: calculateCompatScore(x, self), reverse=True)
        candidates = sorted(
            candidates, key=lambda x: x.compatability_score, reverse=True)
        # identify interested candidates
        interested = list(
            map(int, [x for x in self.interested_ids.split(",") if x]))
        # filter sorted list to only interested candidates
        candidates = filter(lambda x: x.id in interested, candidates)
        return candidates

class Offer(models.Model):
    job_post = models.ForeignKey(JobPost, on_delete=models.CASCADE)
    candidate = models.ForeignKey(CandidateProfile, on_delete=models.CASCADE)
    yearly_salary = models.PositiveIntegerField("Yearly Salary", default=0)
    due_date = models.DateField("Due Date")
    accepted = models.IntegerField("Accepted", default=0)

    def accept(self):
        self.accepted = 1

    def decline(self):
        self.accepted = -1

    def is_expired(self):
        return date.today() > self.due_date

# functions for calculating compatibility score

def bioCompare(candidate, posting):
    numerator = 0
    denominator = 0

    # handle extra chars at end of words, like commas and periods
    for index, item in enumerate(posting):
        if not item[-1].isalpha():
            posting[index] = item[:-1]

    # see how similar candidate bio is to job descrip
    for word in candidate:
        if not word[-1].isalpha():
            word = word[:-1]
        if not len(word):
            continue
        if word in posting:
            numerator += 1
        denominator += 1

    result = numerator/denominator
    return 2*result

def skillCompare(candidate, posting):
    numerator = 0
    denominator = 0

    # handle extra chars at end of words, like commas and periods
    for index, item in enumerate(candidate):
        if not item[-1].isalpha():
            candidate[index] = item[:-1]

    # find number of candidate skills in required skills
    for skill in posting:
        if not skill[-1].isalpha():
            skill = skill[:-1]
        if not len(skill):
            continue
        if skill in candidate:
            numerator += 1
        denominator += 1

    result = numerator/denominator
    return result

def expCheck(canExp, jobType):
    if jobType == "full":
        if canExp > 10:
            return 1
        elif canExp > 5:
            return .5
    else:
        if canExp >= 3:
            return 1
        else:
            return .5

def calculateCompatScore(candidate, job):
    compScore = 0

    canBio = candidate.bio.lower().split()
    canSkills = candidate.skills.lower().split()
    canExp = candidate.experience

    jobDescrip = job.description.lower().split()
    jobSkills = job.des_skills.lower().split()
    jobType = job.type

    compScore += .33*bioCompare(canBio, jobDescrip)
    compScore += .33*skillCompare(canSkills, jobSkills)
    compScore += .34*expCheck(canExp, jobType)

    compScore *= 100

    if compScore > 100:
        compScore = 100

    return round(compScore, 2)


from kids.utils import SparkUtils
from kids.preprocessing import build_training_set
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('kids.workflows')

def preprocess(inputs_path: str, destination_path: str):
    try:
        spark = SparkUtils.build_or_get_session(app_name='preprocessing')
        inputs = spark.read.csv(inputs_path, inferSchema=True, header=True)
        preprocessed = build_training_set(inputs=inputs)
        preprocessed \
            .repartition(8*10) \
            .write \
            .mode('overwrite') \
            .parquet(destination_path)
        print(f'File exported @ {destination_path}')
    except Exception as e:
        logger.error(f'Error while preprocessing dataset: {e}')

def train(parquet_file_path: str):
    try:
        from kids import training as trn
        trn.train(inputs_path=parquet_file_path)
    except Exception as e:
        logger.error(f'Error while training model: {e}')


from rest_framework import (
    serializers,
)

from m3_gar.models import (
    AddhouseTypes,
    AddrObj,
    AddrObjParams,
    AddrObjTypes,
    Apartments,
    ApartmentsParams,
    ApartmentTypes,
    CarplacesParams,
    Houses,
    Steads,
    HousesParams,
    HouseTypes,
    ParamTypes,
    ReestrObjects,
    Rooms,
    RoomsParams,
    RoomTypes,
    SteadsParams,
)
from m3_gar.models.hierarchy import (
    AdmHierarchy,
    Hierarchy,
    MunHierarchy,
)
from m3_rest_gar.consts import (
    CODE_PARAM_TYPES_OFFICIAL,
    GAR_DATE_MAX,
)

class ReestrObjectsSerializer(serializers.ModelSerializer):
    """
    Сериализатор сведений об адресном элементе в части его идентификаторов
    """
    class Meta:
        model = ReestrObjects
        fields = '__all__'

class HierarchySerializer(serializers.ModelSerializer):
    """
    Базовый сериализатор сведений по иерархии
    """
    objectid = ReestrObjectsSerializer()
    parentobjid = ReestrObjectsSerializer()
    has_children = serializers.SerializerMethodField()

    class Meta:
        model = Hierarchy
        fields = '__all__'

    def get_has_children(self, obj):
        return obj.has_children

class MunHierarchySerializer(HierarchySerializer):
    """
    Сериализатор сведений по иерархии в муниципальном делении
    """
    class Meta:
        model = MunHierarchy
        fields = '__all__'

class AdmHierarchySerializer(HierarchySerializer):
    """
    Сериализатор сведений по иерархии в административном делении
    """
    class Meta:
        model = AdmHierarchy
        fields = '__all__'

class ParamTypesSerializer(serializers.ModelSerializer):
    """
    Сериализатор сведений по типу параметра
    """
    class Meta:
        model = ParamTypes
        fields = '__all__'

class ParamListSerializer(serializers.ListSerializer):
    """
    Сериализатор списка сведений о классификаторе параметров адресообразующих
    элементов и объектов недвижимости
    """
    def to_representation(self, data):
        data = data.filter(
            enddate=GAR_DATE_MAX,
        ).select_related(
            'typeid',
        )

        return super().to_representation(data)

class ParamSerializer(serializers.ModelSerializer):
    """
    Сериализатор сведений о классификаторе параметров адресообразующих
    элементов и объектов недвижимости
    """
    typeid = ParamTypesSerializer()

    class Meta:
        fields = '__all__'
        list_serializer_class = ParamListSerializer

class AddrObjParamsSerializer(ParamSerializer):

    class Meta(ParamSerializer.Meta):
        model = AddrObjParams

class ApartmentsParamsSerializer(ParamSerializer):

    class Meta(ParamSerializer.Meta):
        model = ApartmentsParams

class CarplacesParamsSerializer(ParamSerializer):

    class Meta(ParamSerializer.Meta):
        model = CarplacesParams

class HousesParamsSerializer(ParamSerializer):

    class Meta(ParamSerializer.Meta):
        model = HousesParams

class RoomsParamsSerializer(ParamSerializer):

    class Meta(ParamSerializer.Meta):
        model = RoomsParams

class SteadsParamsSerializer(ParamSerializer):

    class Meta(ParamSerializer.Meta):
        model = SteadsParams

class AddrObjTypesSerializer(serializers.ModelSerializer):
    """
    Сериализатор сведений по типам адресных объектов
    """
    class Meta:
        model = AddrObjTypes
        fields = '__all__'

class HierarchicalObjSerializerMixin(
    metaclass=serializers.SerializerMetaclass
):
    """
    Примесь для сериализаторов объектов содержащих сведения об иерархии.
    """
    hierarchy = serializers.SerializerMethodField()

    def get_hierarchy(self, obj):
        data = {}

        for name, model in Hierarchy.get_shortname_map().items():
            hierarchy_instance = model.objects.filter(
                objectid=obj.objectid,
                enddate=GAR_DATE_MAX,
                isactive=True,
            ).select_related(
                'objectid',
                'parentobjid',
            ).first()
            hierarchy_serializer = globals()[f'{model.__name__}Serializer']

            if hierarchy_instance and hierarchy_serializer:
                data[name] = hierarchy_serializer(hierarchy_instance).data

        return data

class AddrObjSerializer(
    HierarchicalObjSerializerMixin,
    serializers.ModelSerializer
):
    """
    Сериализатор сведений классификатора адресообразующих элементов
    """
    params = AddrObjParamsSerializer(many=True)
    type_full_name = serializers.SerializerMethodField()

    # На момент описания моделей AddrObjTypes никак не связывается с AddrObj
    # Существующее поле AddrObj.typename - текстовое представление (ул, пер, г, и т.п.)
    # ??? = AddrObjTypesSerializer()

    class Meta:
        model = AddrObj
        fields = '__all__'

    def get_type_full_name(self, obj):
        return obj.type_full_name.lower()

class HouseTypesSerializer(serializers.ModelSerializer):
    """
    Сериализатор сведений по типам домов
    """
    class Meta:
        model = HouseTypes
        fields = '__all__'

class AddhouseTypesSerializer(serializers.ModelSerializer):
    """
    Сериализатор сведений по дополнительным типам домов
    """
    class Meta:
        model = AddhouseTypes
        fields = '__all__'

class HousesSerializer(
    HierarchicalObjSerializerMixin,
    serializers.ModelSerializer
):
    """
    Сериализатор сведений по номерам домов улиц городов и населенных пунктов
    """
    params = HousesParamsSerializer(many=True)
    housetype = HouseTypesSerializer()
    addtype1 = AddhouseTypesSerializer()
    addtype2 = AddhouseTypesSerializer()

    class Meta:
        model = Houses
        fields = '__all__'

class SteadsSerializer(
    HierarchicalObjSerializerMixin,
    serializers.ModelSerializer
):
    """
    Сериализатор сведений по земельным участкам
    """

    params = SteadsParamsSerializer(many=True)

    class Meta:
        model = Steads
        fields = '__all__'

class ApartmentTypesSerializer(serializers.ModelSerializer):
    """
    Сериализатор сведений по типам помещений
    """
    class Meta:
        model = ApartmentTypes
        fields = '__all__'

class ApartmentsSerializer(serializers.ModelSerializer):
    """
    Сериализатор сведений по помещениям
    """
    params = ApartmentsParamsSerializer(many=True)
    aparttype = ApartmentTypesSerializer()

    class Meta:
        model = Apartments
        fields = '__all__'

class RoomTypesSerializer(serializers.ModelSerializer):
    """
    Сериализатор сведений по типам комнат
    """
    class Meta:
        model = RoomTypes
        fields = '__all__'

class RoomsSerializer(serializers.ModelSerializer):
    """
    Сериализатор сведений по комнатам
    """
    params = RoomsParamsSerializer(many=True)
    roomtype = RoomTypesSerializer()

    class Meta:
        model = Rooms
        fields = '__all__'


from django.contrib.auth.models import User
from .models import Ingredient, Recipe, Step
from rest_framework import serializers

class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ['url', 'username', 'id']

class IngredientsSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(label='ID', read_only=False)
    class Meta:
        model = Ingredient
        fields = ['id', 'ingredient']

class StepSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(label='ID', read_only=False)
    class Meta:
        model = Step
        fields = ['id', 'step_text']

class RecipeSerializer(serializers.ModelSerializer):
    steps = StepSerializer(many=True)
    ingredients = IngredientsSerializer(many=True)
    # steps = serializers.StringRelatedField(many=True)
    # ingredients = serializers.StringRelatedField(many=True)
    user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
    class Meta:
        model = Recipe
        fields = ['pk', 'name', 'user', 'steps', 'ingredients']

    def create(self, validated_data):
        # super(RecipeSerializer, self).create(self)
        ing_data = validated_data.pop('ingredients')
        steps_data = validated_data.pop('steps')
        recipe = Recipe.objects.create(**validated_data)
        for ing in ing_data:
            Ingredient.objects.create(recipe=recipe, **ing)
        for steps in steps_data:
            Step.objects.create(recipe=recipe, **steps)
        return recipe

    def get_foreign_field_data(self, validated_data, field_name):
        try:
            return validated_data.pop(field_name)
        except KeyError:
            return None

    def update_steps(self, steps_data, instance):
        if steps_data is not None:
            for i, steps in enumerate(steps_data):
                print(steps)
                if steps.get('id', None) is not None:
                    step = Step.objects.get(id=steps['id'])
                    step.step_text = steps.get('step_text', step.step_text)
                    step.recipe = instance
                    step.save()
                elif steps.get('step_text', None) is not None:
                    Step.objects.create(recipe=instance, **steps)

    def update_ingredints(self, ingredient_data, instance):
        if ingredient_data is not None:
            for i, _ing in enumerate(ingredient_data):
                if _ing['id']:
                    ingred = Ingredient.objects.get(id=_ing['id'])
                    ingred.ingredient = _ing.get('ingredient', ingred.ingredient)
                    ingred.recipe = instance
                    ingred.save()
                elif _ing.get('ingredient', None) is not None:
                    Ingredient.objects.create(recipe=instance, **_ing)

    def update(self, instance, validated_data, **kwargs):
        print('valid data', validated_data)
        instance.name = validated_data.get('name', instance.name)
        instance.save()

        # updates foreign keys if id is provided else creates a new field
        steps_data = self.get_foreign_field_data(validated_data, 'steps')
        self.update_steps(steps_data, instance)
        ingredients_data = self.get_foreign_field_data(validated_data, 'ingredients')
        self.update_ingredints(ingredients_data, instance)

        return instance


import boto3
import uuid
import json

def lambda_handler(event, context):
    print(json.dumps(event))

    record = event['Records'][0]
    #collecting bucket name and key
    s3bucket = record['s3']['bucket']['name']
    s3object = record['s3']['object']['key']

    #extracting the file name from the key
    file = s3object.split("/")[3]
    s3Path = f's3://{s3bucket}/{s3object}'
    jobName = f'{file}-{str(uuid.uuid4())}'
    #setting the output path (transcripts will be stored under "s3://transcripts/" folder)
    outputKey = f'transcripts/{file}-transcript.json'

    client = boto3.client('transcribe')

    response = client.start_transcription_job(
        TranscriptionJobName=jobName,
        LanguageCode='fr-FR',
        Media={'MediaFileUri': s3Path},
        OutputBucketName=s3bucket,
        OutputKey=outputKey
    )

    print(json.dumps(response, default=str))

    return {
        'TranscriptionJobName': response['TranscriptionJob']['TranscriptionJobName']
    }


from bayes_opt import BayesianOptimization, SequentialDomainReductionTransformer
from catboost import CatBoostRegressor
from sklearn import model_selection

def catboost_cv(learning_rate, l2_leaf_reg, bagging_temperature, depth, x_train, y_train):
    """
    Function to perform cross validation of an CatBoost model
    :param learning_rate:
    :param l2_leaf_reg:
    :param bagging_temperature:
    :param depth:
    :param x_train:
    :param y_train:
    :return:
    """

    params = {
        'loss_function': 'RMSE',
        'eval_metric': 'RMSE',
        'iterations': 999,
        'learning_rate': learning_rate,
        'random_seed': 42,
        'l2_leaf_reg': l2_leaf_reg,
        'bagging_temperature': bagging_temperature,
        'depth': int(depth),
        'early_stopping_rounds': 10,
        'od_pval': 10e-2,
        'task_type': 'GPU',
        'logging_level': 'Silent',
        'boosting_type': 'Plain'
    }

    catboost = CatBoostRegressor(**params)

    cv_result = model_selection.cross_validate(estimator=catboost, X=x_train, y=y_train)

    mse = cv_result['test_score'] ** 2

    return -1.0 * mse

def optimize_catboost(x_train, y_train, pbounds, n_iter, init_points):
    """
    Performs Bayesian Optimization of an CatBoost Model
    :param x_train:
    :param y_train:
    :param pbounds:
    :param n_iter:
    :param init_points:
    :return:
    """

    def catboost_crossval(learning_rate, l2_leaf_reg, bagging_temperature, depth):
        """
        Wrapper for catboost_cv
        :param learning_rate:
        :param l2_leaf_reg:
        :param bagging_temperature:
        :param depth:
        :return:
        """
        return catboost_cv(learning_rate, l2_leaf_reg, bagging_temperature, depth, x_train, y_train)

    optimizer = BayesianOptimization(
        f=catboost_crossval,
        pbounds=pbounds,
        bounds_transformer=SequentialDomainReductionTransformer(),
        random_state=42,
        verbose=2
    )

    optimizer.maximize(n_iter=n_iter, init_points=init_points, acq='ei')

    return optimizer


"""This module contains an operation to set the deep resolver path."""

# =============================================================================
# IMPORTS
# =============================================================================

# Future
from __future__ import annotations

# Standard Library
import logging
from typing import TYPE_CHECKING, List, Optional, Union

# Houdini Toolbox
from houdini_toolbox.pyfilter.operations.operation import (
    PyFilterOperation,
    log_filter_call,
)
from houdini_toolbox.pyfilter.property import get_property, set_property

if TYPE_CHECKING:
    import argparse

    from houdini_toolbox.pyfilter.manager import PyFilterManager

_logger = logging.getLogger(__name__)

# =============================================================================
# CLASSES
# =============================================================================

class SetDeepImage(PyFilterOperation):
    """Operation to modify deep image generation.

    :param manager: The manager this operation is registered with.

    """

    def __init__(self, manager: PyFilterManager) -> None:
        super().__init__(manager)

        self._all_passes = False
        self._disable_deep_image = False

        self._resolver = None
        self._filename = None
        self._compositing = None
        self._deepcompression = None
        self._depth_planes = None
        self._mipmaps = None
        self._ofsize = None
        self._ofstorage = None
        self._pzstorage = None
        self._zbias = None

    # -------------------------------------------------------------------------
    # NON-PUBLIC METHODS
    # -------------------------------------------------------------------------

    def _modify_deep_args(self, deep_args: List[str]) -> None:
        """Modify the args either in place or by adding to them.

        :param deep_args: The list of deep resolver args.
        :return:

        """
        arg_names = (
            "filename",
            "compositing",
            "deepcompression",
            "depth_planes",
            "mipmaps",
            "ofsize",
            "ofstorage",
            "pzstorage",
            "zbias",
        )

        # Look for each of our known args.
        for arg_name in arg_names:
            # Try to get the equivalent property on this object.
            value = getattr(self, arg_name)

            # Found a value we might be able to set.
            if value is not None:
                # The arg is already in the list so we need to modify the
                # existing value with our value.
                if arg_name in deep_args:
                    # The value is the next item in the list so get the index
                    # and modify the next one.
                    idx = deep_args.index(arg_name)
                    deep_args[idx + 1] = value

                # The arg is not currently in the args so add the name and value.
                else:
                    deep_args.extend((arg_name, value))

    # -------------------------------------------------------------------------
    # PROPERTIES
    # -------------------------------------------------------------------------

    @property
    def all_passes(self) -> bool:
        """Modify deep resolver during all render types."""
        return self._all_passes

    @property
    def compositing(self) -> Optional[int]:
        """Pre-composite the samples."""
        return self._compositing

    @property
    def deepcompression(self) -> Optional[int]:
        """Compression value."""
        return self._deepcompression

    @property
    def depth_planes(self) -> Optional[str]:
        """Special planes."""
        return self._depth_planes

    @property
    def disable_deep_image(self) -> bool:
        """Disable deep image generation."""
        return self._disable_deep_image

    @property
    def filename(self) -> Optional[str]:
        """The deep image path to set."""
        return self._filename

    @property
    def mipmaps(self) -> Optional[int]:
        """Create MIP mapped images."""
        return self._mipmaps

    @property
    def ofsize(self) -> Optional[int]:
        """The opacity storage size."""
        return self._ofsize

    @property
    def ofstorage(self) -> Optional[str]:
        """The opacity bit depth."""
        return self._ofstorage

    @property
    def pzstorage(self) -> Optional[str]:
        """The depth bit depth."""
        return self._pzstorage

    @property
    def resolver(self) -> Optional[str]:
        """The type of deep to generate."""
        return self._resolver

    @property
    def zbias(self) -> Optional[float]:
        """Compression bias."""
        return self._zbias

    # -------------------------------------------------------------------------
    # STATIC METHODS
    # -------------------------------------------------------------------------

    @staticmethod
    def build_arg_string(  # pylint: disable=arguments-differ,too-many-arguments
        disable_deep_image: bool = False,
        deep_all_passes: bool = False,
        deep_image_path: Optional[str] = None,
        resolver: Optional[str] = None,
        compositing: Optional[bool] = None,
        compression: Optional[int] = None,
        depth_planes: Optional[Union[List[str], str]] = None,
        mipmaps: Optional[bool] = None,
        ofsize: Optional[int] = None,
        ofstorage: Optional[str] = None,
        pzstorage: Optional[str] = None,
        zbias: Optional[float] = None,
    ) -> str:
        """Build an argument string for this operation.

        :param disable_deep_image: Whether to disable the deep image.
        :param deep_all_passes: Whether to modify the deep resolver
                                during all render types.
        :param deep_image_path: The path to the output deep image.
        :param resolver: The deep resolver to run.
        :param compositing: Whether to pre-composite the values.
        :param compression: The compression value.
        :param depth_planes: A list of special planes.
        :param mipmaps: Whether to create MIP mapped images.
        :param ofsize: The opacity size (float vs vector).
        :param ofstorage: The opacity bit depth:
        :param pzstorage: The Z depth bit depth:
        :param zbias: The compression bias.
        :return: The constructed argument string.

        """
        args = []

        if disable_deep_image:
            args.append("--disable-deep-image")

        if deep_image_path is not None:
            args.append(f"--deep-image-path={deep_image_path}")

        if resolver is not None:
            args.append(f"--deep-resolver={resolver}")

        if compositing is not None:
            args.append(f"--deep-compositing={compositing}")

        if compression is not None:
            args.append(f"--deep-compression={compression}")

        if depth_planes is not None:
            if not isinstance(depth_planes, str):
                depth_planes = ",".join(depth_planes)

            args.append(f"--deep-depth-planes={depth_planes}")

        if mipmaps is not None:
            args.append(f"--deep-mipmaps={mipmaps}")

        if ofsize is not None:
            args.append(f"--deep-ofsize={ofsize}")

        if ofstorage is not None:
            args.append(f"--deep-ofstorage={ofstorage}")

        if pzstorage is not None:
            args.append(f"--deep-pzstorage={pzstorage}")

        if zbias is not None:
            args.append(f"--deep-zbias={zbias}")

        if deep_all_passes:
            args.append("--deep-all-passes")

        return " ".join(args)

    @staticmethod
    def register_parser_args(parser: argparse.ArgumentParser) -> None:
        """Register interested parser args for this operation.

        :param parser: The argument parser to attach arguments to.
        :return:

        """
        parser.add_argument("--deep-image-path", dest="deep_image_path")

        parser.add_argument(
            "--deep-all-passes", action="store_true", dest="deep_all_passes"
        )

        parser.add_argument(
            "--disable-deep-image", action="store_true", dest="disable_deep_image"
        )

        parser.add_argument(
            "--deep-resolver", choices=("camera", "shadow"), dest="deep_resolver"
        )

        parser.add_argument("--deep-compression", type=int, dest="deep_compression")

        parser.add_argument("--deep-compositing", type=int, dest="deep_compositing")

        parser.add_argument("--deep-depth-planes", dest="deep_depth_planes")

        parser.add_argument(
            "--deep-mipmaps", type=int, choices=(0, 1), dest="deep_mipmaps"
        )

        parser.add_argument(
            "--deep-ofsize", type=int, choices=(1, 3), dest="deep_ofsize"
        )

        parser.add_argument(
            "--deep-ofstorage",
            choices=("real16", "real32", "real64"),
            dest="deep_ofstorage",
        )

        parser.add_argument(
            "--deep-pzstorage",
            choices=("real16", "real32", "real64"),
            dest="deep_pzstorage",
        )

        parser.add_argument("--deep-zbias", type=float, dest="deep_zbias")

    # -------------------------------------------------------------------------
    # METHODS
    # -------------------------------------------------------------------------

    @log_filter_call
    def filter_camera(self) -> None:
        """Apply camera properties.

        :return:

        """
        render_type = get_property("renderer:rendertype")

        if not self.all_passes and render_type != "beauty":
            _logger.warning("Not a beauty render, skipping deepresolver")
            return

        if self.disable_deep_image:
            _logger.info("Disabling deep resolver")
            set_property("image:deepresolver", [])

        else:
            # Look for existing args.
            deep_args = get_property("image:deepresolver")

            # If deep rendering is not enabled the args will be empty.
            if not deep_args:
                # If a resolver type and filename was passed then we will create
                # args for the resolver type to enable deep output.
                if self.resolver and self.filename:
                    deep_args = [self.resolver]

                # Log an error and abort.
                else:
                    _logger.error("Cannot set deepresolver: deep output is not enabled")

                    return

            # Modify the args to include any passed along options.
            self._modify_deep_args(deep_args)

            _logger.debug(
                "Setting 'image:deepresolver': %s",
                " ".join([str(arg) for arg in deep_args]),
            )

            set_property("image:deepresolver", deep_args)

    def process_parsed_args(self, filter_args: argparse.Namespace) -> None:
        """Process any parsed args that the operation may be interested in.

        :param filter_args: The argparse namespace containing processed args.
        :return:

        """
        if filter_args.disable_deep_image:
            self._disable_deep_image = True

        if filter_args.deep_all_passes:
            self._all_passes = True

        if filter_args.deep_image_path is not None:
            self._filename = filter_args.deep_image_path

        if filter_args.deep_resolver is not None:
            self._resolver = filter_args.deep_resolver

        if filter_args.deep_compositing is not None:
            self._compositing = filter_args.deep_compositing

        if filter_args.deep_compression is not None:
            self._deepcompression = filter_args.deep_compression

        if filter_args.deep_depth_planes is not None:
            self._depth_planes = filter_args.deep_depth_planes

        if filter_args.deep_mipmaps is not None:
            self._mipmaps = filter_args.deep_mipmaps

        if filter_args.deep_ofsize is not None:
            self._ofsize = filter_args.deep_ofsize

        if filter_args.deep_ofstorage is not None:
            self._ofstorage = filter_args.deep_ofstorage

        if filter_args.deep_pzstorage is not None:
            self._pzstorage = filter_args.deep_pzstorage

        if filter_args.deep_zbias is not None:
            self._zbias = filter_args.deep_zbias

    def should_run(self) -> bool:
        """Determine whether this operation should be run.

        This operation will run if the disable option is set or any of the
        other options which would modify the args are set.

        :return: Whether this operation should run.

        """
        if self.disable_deep_image:
            return True

        return any(
            (
                self.filename,
                self.resolver,
                self.compositing is not None,
                self.deepcompression is not None,
                self.depth_planes,
                self.mipmaps is not None,
                self.ofsize is not None,
                self.ofstorage,
                self.pzstorage,
                self.zbias is not None,
            )
        )


import torch
from torch.utils.data.dataloader import DataLoader
import os

class Dataset(torch.utils.data.Dataset):
  'Characterizes a dataset for PyTorch'
  def __init__(self, imgs_path, labels_path):
        'Initialization'
        self.labels = os.listdir(labels_path)
        self.images= os.listdir(imgs_path)

  def __len__(self):
        'Denotes the total number of samples'
        return len(self.list_IDs)

  def __getitem__(self, index):
        'Generates one sample of data'
        # Select sample
        current_img = self.images[index]
        current_label = self.labels[index]

        # Load data and get label
        img = torch.load(current_img)
        label = torch.load(current_label)

        return img, label

#print(os.listdir(''))
curr_dataset = Dataset("rep_learning_data/rgb/aldine/rgb","rep_learning_data/aldine_class_object/class_object")
training_generator = torch.utils.data.DataLoader(training_set, **params)

params = {'batch_size': 64,
          'shuffle': True,
          'num_workers': 6}


import time
import requests

_head = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3423.2 Safari/537.36"
}

_api = "https://www.sojson.com/open/api/weather/json.shtml?city=%s"

class Weather():

    def __init__(self, address):
        self.address = address
        self.weather = self.format_weather()

    def link_api(self, address):
        count = 0
        while True:
            res = requests.get(_api % address, headers=_head, timeout=10)
            count += 1
            if res.status_code == 200:
                return res.json()
            if count > 5:
                return None
            time.sleep(4)

    def format_weather(self):
        source = self.link_api(self.address)
        if source is None:
            return None
        weather_dict = {
            "今日天气": source["data"]["forecast"][0]["type"],
            "平均温度": source["data"]["wendu"],
            "最高温度": source["data"]["forecast"][0]["high"],
            "最低温度": source["data"]["forecast"][0]["low"],
            "湿度": source["data"]["shidu"],
            "PM2.5": source["data"]["pm25"],
            "空气质量": source["data"]["quality"],
            "风力": source["data"]["forecast"][0]["fl"],
            "风向": source["data"]["forecast"][0]["fx"]
        }
        return weather_dict

    def get_weather(self):
        return self.weather

if __name__ == "__main__":

    """以下是实验"""

    data = Weather("成都")
    print(data.weather)

    dictionary = {'city': '成都', 'date': '20180526',
    'data':
    {'ganmao': '儿童、老年人及心脏、呼吸系统疾病患者人群应减少长时间或高强度户外锻炼', 'pm25': 33.0, 'wendu': '24', 'quality': '轻度污染', 'pm10': 63.0,
    'yesterday':
    {'aqi': 118.0,'notice': '阴晴之间，谨防紫外线侵扰', 'date': '25日星期五', 'low': '低温 18.0℃', 'sunset': '19:57', 'fx': '无持续风向', 'type': '多云', 'fl': '<3级', 'sunrise': '06:05', 'high': '高温 29.0℃'},
    'forecast':
    [
        {'aqi': 54.0, 'notice': '雨虽小，注意保暖别感冒', 'date': '26日星期六', 'low': '低温 17.0℃', 'sunset': '19:57', 'fx': '无持续风向', 'type': '小雨', 'fl': '<3级', 'sunrise': '06:04', 'high': '高温 26.0℃'},
        {'aqi': 58.0, 'notice': '阴晴之间，谨防紫外线侵扰', 'date': '27日星期日', 'low': '低温 16.0℃', 'sunset': '19:58', 'fx': '无持续风向', 'type': '多云', 'fl': '<3级', 'sunrise': '06:04', 'high': '高温 29.0℃'},
        {'aqi': 66.0, 'notice': '阴晴之间，谨防紫外线侵扰', 'date': '28日星期一', 'low': '低温 17.0℃', 'sunset': '19:59', 'fx': '无持续风向', 'type': '多云', 'fl': '<3级', 'sunrise': '06:04', 'high': '高温 28.0℃'},
        {'aqi': 71.0, 'notice': '阴晴之间，谨防紫外线侵扰', 'date': '29日星期二', 'low': '低温 17.0℃', 'sunset': '19:59', 'fx': '无持续风向', 'type': '多云', 'fl': '<3级', 'sunrise': '06:03', 'high': '高温 27.0℃'},
        {'aqi': 68.0, 'notice': '阴晴之间，谨防紫外线侵扰', 'date': '30日星期三', 'low': '低温 18.0℃', 'sunset': '20:00', 'fx': '无持续风向', 'type': '多云', 'fl': '<3级', 'sunrise': '06:03', 'high': '高温 25.0℃'}
        ],
    'shidu': '78%'}, 'status': 200, 'message': 'Success !', 'count': 1102}


#!/bin/env python3
import json

import sseclient

messages = sseclient.SSEClient("https://www.blaseball.com/events/streamData")

last_data = ""
last_game = {}
for m in messages:
    if last_data == m.data:
        print("DUPLICATE DATA")
    else:
        print("changed data")

    j = json.loads(m.data)

    schedule = j["value"]["games"]["schedule"]

    g = next(s for s in schedule if s["awayTeamNickname"] == "Lift" or s["homeTeamNickname"] == "Lift")

    if last_game == g:
        print("DUPLICATE GAME\n\n")
    else:
        print("changed game\n\n")

    last_game = g
    last_data = m.data


#! /usr/bin/python

import string, os
import pygame
pygame.init()

font = pygame.font.SysFont("Courier", 100)

for char in string.printable:
	if char != " " and char in string.whitespace:
		continue
	index = ord(char)
	img = font.render(char, True, (255, 255, 255))#.convert(24)
	pygame.image.save(img, "%i.png" % index)


#! /usr/bin/env python

# bdf.py -- PBD 2015/06

# This class provides access to EVLA/ALMA Binary Data Format (BDF)
# files.  The approach used here is based loosely on 'bdfparse.py'
# originally by Peter Williams.  So far this is somewhat targeted
# to EVLA/WIDAR data files, it may not handle all the ALMA variants.

from lxml import etree, objectify

import os
import sys
import string
import re
import mmap
import math
import numpy
from copy import deepcopy

try:
    from progressbar import ProgressBar
except ImportError:
    ProgressBar = None

from .mime import MIMEPart, MIMEHeader

def basename_noext(path):
    return os.path.basename(os.path.splitext(path)[0])

# TODO find a better way to get the namespace automatically?
_ns = '{http://Alma/XASDM/sdmbin}'
def _stripns(tag):
    return re.sub('{.+}','',tag)

def ant2bl(i,j=None):
    """Returns baseline index for given antenna pair.  Will accept
    two args, or a list/tuple/etc.  Uses 0-based indexing"""
    if j is None:
        (a1,a2) = sorted(i[:2])
    else:
        (a1,a2) = sorted((i,j))
    # could raise error if a2==a1, either are negative, etc
    return (a2*(a2-1))/2 + a1

def bl2ant(i):
    """Returns antenna pair for given baseline index.  All are 0-based."""
    a2 = int(0.5*(1.0+math.sqrt(1.0+8.0*i)))
    a1 = i - a2*(a2-1)/2
    return a1, a2

class BDF(object):
    """
    Class representing a single BDF file.  For example:

        b = bdf.BDF('uid____evla_bdf_1433189755525')

    Individual integration data is returned as BDFIntegration objects via
    either b.get_integration(idx) or b[idx].  Other useful methods include:

        b.basebands      # list of baseband ids
        b.spws           # list of spectral windows per baseband
        b.numAntenna     # number of antennas
        b.numBaseline    # number of baselines
        b.numIntegration # number of integrations in file
        b.sdmDataHeader  # lxml objectify version of full header

    """

    def __init__(self, fname):
        self.fname = fname
        self.fp = open(fname, 'r')
        self.mmdata = mmap.mmap(self.fp.fileno(), 0, mmap.MAP_PRIVATE,
                mmap.PROT_READ)
        self.read_mime()
        self.parse_spws()

    # Size in bytes of each data element. In principle, the crossData
    # type needs to be read from the headers while all others have
    # pre-set values...
    bin_dtype_size = {
            'flags':           4, # INT32
            'actualTimes':     8, # INT64
            'actualDurations': 8, # INT64
            'zeroLags':        4, # FLOAT32
            'autoData':        4, # FLOAT32
            'crossData':       4, # FLOAT32 but should be determined from file
            }

    # Basic data type for each array.  Note, does not necessarily
    # match up with the sizes above due to how BDF defines the 'size'
    # attribute..
    bin_dtype = {
            'autoData':        numpy.float32,
            'crossData':       numpy.complex64,
            }

    def read_mime(self,full_read=False):
        self.fp.seek(0,0) # Go back to start
        if not self.fp.readline().startswith('MIME-Version:'):
            raise RuntimeError('Invalid BDF: missing MIME-Version')

        # First we need to read and parse only the main XML header in order
        # to get sizes of the binary parts.  Note, the info stored in
        # self.bin_size is in bytes, rather than the weird BDF units.
        mime_hdr = MIMEPart(self.fp).hdr
        self.top_mime_bound = mime_hdr.boundary
        sdmDataMime = MIMEPart(self.fp,boundary=self.top_mime_bound)
        if sdmDataMime.loc != 'sdmDataHeader.xml':
            raise RuntimeError('Invalid BDF: missing sdmDataHeader.xml')
        self.sdmDataHeader = objectify.fromstring(sdmDataMime.body)
        self.bin_size = {}
        self.bin_axes = {}
        for e in self.sdmDataHeader.iter():
            if 'size' in e.attrib.keys() and 'axes' in e.attrib.keys():
                binname = _stripns(e.tag)
                self.bin_size[binname] = int(e.attrib['size']) \
                        * self.bin_dtype_size[binname]
                self.bin_axes[binname] = e.attrib['axes'].split()

        # For EVLA, we can read the first integration, note the file offset
        # in order to determine the size, then seek to each integration as
        # requested, rather than parsing the whole file here.
        if 'EVLA' in mime_hdr['Content-Description'][0] and not full_read:
            self.offset_ints = self.fp.tell() # Offset in file to first integ
            self.mime_ints = [MIMEPart(self.fp,
                boundary=self.top_mime_bound,
                binary_size=self.bin_size,
                recurse=True),]
            # Compute size of each integration section:
            self.size_ints = self.fp.tell() - self.offset_ints
            numints = int((os.path.getsize(self.fname)-self.offset_ints)/self.size_ints)
            self.mime_ints += [None,]*(numints-1)

        # This is the more general way to do it that does not assume
        # each integration (including XML and MIME headers) has the
        # same size in the file.  In this case, go back to the beginning
        # and parse the whole MIME structure to map it out.
        else:
            self.fp.seek(0,0) # reset to start again
            full_mime = MIMEPart(self.fp,
                    recurse=True, binary_size=self.bin_size)
            self.mime_ints = full_mime.body[1:]

    def _raw(self,idx):
        if self.mime_ints[idx] is not None: return self.mime_ints[idx]
        # Need to read this one
        self.fp.seek(self.offset_ints + idx*self.size_ints, 0)
        #self.mime_ints[idx] = self.read_mime_part(boundary=self.top_mime_bound,recurse=True)
        self.mime_ints[idx] = MIMEPart(self.fp,
                boundary=self.top_mime_bound,
                binary_size=self.bin_size,
                recurse=True)
        return self.mime_ints[idx]

    @property
    def projectPath(self):
        return self.sdmDataHeader.attrib['projectPath']

    @property
    def numIntegration(self):
        return len(self.mime_ints)

    @property
    def numAntenna(self):
        return int(self.sdmDataHeader.numAntenna)

    @property
    def numBaseline(self):
        return (self.numAntenna*(self.numAntenna-1))/2

    @property
    def startTime(self):
        return float(self.sdmDataHeader.startTime)/86400.0e9

    def parse_spws(self):
        self.basebands = []
        self.spws = []
        # Offsets into the cross and data arrays where this spw
        # can be found.  This info could be reconstructed later
        # but seems convenient to do it here.
        cross_offset = 0
        auto_offset = 0
        self.spws = []
        for bb in self.sdmDataHeader.dataStruct.baseband:
            bbname = bb.attrib['name']
            self.basebands.append(bbname)
            for spw_elem in bb.spectralWindow:
                # Build a list of spectral windows for each baseband
                spw = BDFSpectralWindow(spw_elem,cross_offset,auto_offset)
                cross_offset += spw.dsize('cross')
                auto_offset += spw.dsize('auto')
                self.spws.append(spw)

    def get_integration(self,idx):
        return BDFIntegration(self,idx)

    def __getitem__(self,idx):
        return self.get_integration(idx)

    def zerofraction(self,spwidx='all',type='cross'):
        """Return zero fraction for the entire BDF.  This is done by loading
        each integration's data so may take a while."""
        tot = 0.0
        for i in self:
            tot += i.zerofraction(spwidx,type)
        return tot / self.numIntegration

    def get_data(self,spwidx='all',type='cross',scrunch=False,
            fscrunch=False,frange=None,trange=None,bar=False):
        """Returns an array containing all integrations for the specified
        baseband, spw and data type.  If scrunch=True, all integrations
        will be averaged."""
        chidx = -2 # index of spectral channels
        # Figure out ranges:
        if trange is None:
            i0 = 0
            i1 = self.numIntegration
        else:
            i0 = trange[0]
            i1 = trange[1]
        # Read first integration to get shapes, etc
        nsubout = i1 - i0
        subdat = self.get_integration(i0).get_data(spwidx,type)
        if scrunch:
            dshape = subdat.shape
        else:
            dshape = (nsubout,) + subdat.shape
        if fscrunch:
            dshape = dshape[:chidx] + dshape[chidx+1:]
        result = numpy.zeros(dshape,dtype=subdat.dtype)
        if bar and ProgressBar is not None:
            b = ProgressBar()
        else:
            b = lambda x: x
        for i in b(range(i0,i1)):
            if fscrunch:
                if frange is None:
                    dat = self.get_integration(i).get_data(spwidx,type).mean(chidx)
                else:
                    dat = self.get_integration(i).get_data(spwidx,type).take(range(*frange),axis=chidx).mean(chidx)
            else:
                dat = self.get_integration(i).get_data(spwidx,type)
            if scrunch:
                result += dat
            else:
                result[i-i0] = dat
        if scrunch:
            result /= float(nsubout)
        return result

class BDFSpectralWindow(object):
    """Class that represents spectral window information present in BDF files,
    including storing appropriate offsets into the main data array.  Should be
    initialized from the spectralWindow XML element from the main BDF
    header."""

    def __init__(self, spw_elem, cross_offset=None, auto_offset=None):
        self._attrib = spw_elem.attrib
        self.cross_offset = cross_offset
        self.auto_offset = auto_offset

    @property
    def numBin(self):
        return int(self._attrib['numBin'])

    @property
    def numSpectralPoint(self):
        return int(self._attrib['numSpectralPoint'])

    # These two are not listed in the BDF spec but appear in EVLA data:
    @property
    def sw(self):
        return int(self._attrib['sw'])

    @property
    def swbb(self):
        return self._attrib['swbb']

    # Should uniquely identify a sw?
    @property
    def name(self):
        return self.swbb + '-' + str(self.sw)

    def npol(self,type):
        """Return number of polarization array elements for the given data
        type (cross or auto)."""
        try:
            if type[0].lower()=='c':
                return len(self._attrib['crossPolProducts'].split())
            elif type[0].lower()=='a':
                # Good enough?
                l = len(self._attrib['sdPolProducts'].split())
                return 4 if l==3 else l # 3==4 in BDF math! :)
        except KeyError:
            return 0

    def dshape(self,type):
        """Return shape tuple of data array for this spectral window,
        in number of data elements (real for auto, complex for cross)."""
        return (self.numBin, self.numSpectralPoint, self.npol(type))

    def dsize(self,type):
        """Return size of data array for this spectral window, in number of
        data elements (real for auto, complex for cross)."""
        return numpy.product(self.dshape(type))

    @staticmethod
    def dims_match(spwlist,type):
        """Given a list of BDFSpectralWindow objects, return true if all
        of them have consistent array dimensions."""
        if len(spwlist)==1:
            return True
        for spw in spwlist[1:]:
            if spwlist[0].dshape(type) != spw.dshape(type):
                return False
        return True

class BDFIntegration(object):
    """
    Describes and holds data for a single intgration within a BDF file.
    This should be derived from an existing BDF object using
    get_integration() or indexing, ie:

        b = bdf.BDF('some_file')

        # Get the 5th integration, these two are equivalent:
        i = b.get_integration(5)
        i = b[5]

        # Read the cross-corr data array for spectral window 0
        dat = i.get_data(0)

    Other potentially useful info:

        i.basebands            # list of baseband IDs
        i.spws                 # dict of spws per baseband
        i.numAntenna           # obvious
        i.numBaseline          # "
        i.sdmDataSubsetHeader  # lxml objectify version of full sub-header

    """

    def __init__(self,bdf,idx):
        # Get the main header
        self.sdmDataSubsetHeader = objectify.fromstring(
                bdf._raw(idx).body[0].body)
        # Copy some info from the BDF headers
        self.basebands = bdf.basebands
        self.spws = bdf.spws
        self.bin_axes = bdf.bin_axes
        self.numAntenna = bdf.numAntenna
        self.numBaseline = bdf.numBaseline
        # Get the binary data
        self.data = {}
        for m in bdf._raw(idx).body[1:]:
            btype = basename_noext(m.loc)
            bsize = bdf.bin_size[btype] # size of the binary blob in bytes
            baxes = self.bin_axes[btype]
            # Determine outer step size for the array, either baselines
            # antennas of baseline+antenna.  We can't apply the other
            # dimensions here because the number of elements can vary
            # per spw.
            if baxes[0]=='BAL' and baxes[1]=='ANT':
                shape=(self.numBaseline+self.numAntenna,-1)
            elif baxes[0]=='BAL':
                shape=(self.numBaseline,-1)
            elif baxes[0]=='ANT':
                shape=(self.numAntenna,-1)
            else:
                shape=(-1,) # Don't know what to do, just leave flat array
            self.data[btype] = numpy.frombuffer(bdf.mmdata[m.body:m.body+bsize],
                    dtype=bdf.bin_dtype[btype]).reshape(shape)

    @property
    def projectPath(self):
        return self.sdmDataSubsetHeader.attrib['projectPath']

    @property
    def time(self):
        return float(self.sdmDataSubsetHeader.schedulePeriodTime.time)/86400.0e9

    @property
    def interval(self):
        return float(self.sdmDataSubsetHeader.schedulePeriodTime.interval)*1e-9

    def get_data(self,spwidx='all',type='cross'):
        """
        Return the data array for the given subset.  Inputs are:

            spwidx:    spw index within file
            type:      'cross' or 'auto' (default 'cross')

        The returned array shape is (nBl/nAnt, nBin, nSpp, nPol).

        If spwidx is 'all' and the array dimensions of all spectral
        windows match, all will be returned in a single array.  In this case
        the returned dimensions will be (nBl/nAnt, nSpw, nBin, nSpp, nPol).
        """
        if type[0].lower()=='c':
            loc = 'crossData'
        elif type[0].lower()=='a':
            loc = 'autoData'
        else:
            raise RuntimeError('Unsupported data type')
        if spwidx=='all':
            if not BDFSpectralWindow.dims_match(self.spws,type):
                raise RuntimeError('BDFIntegration: ' +
                        'mixed array dimensions, spws must be ' +
                        'retrieved indivdually')
            dshape = (-1, len(self.spws)) + self.spws[0].dshape(type)
            return self.data[loc].reshape(dshape)
        spw = self.spws[spwidx]
        if loc == 'crossData':
            offs = spw.cross_offset
        elif loc == 'autoData':
            offs = spw.auto_offset
        else:
            raise RuntimeError('Unsupported data type')
        dsize = spw.dsize(type)
        dshape = (-1,) + spw.dshape(type)
        return self.data[loc][:,offs:offs+dsize].reshape(dshape)

    def zerofraction(self,spwidx='all',type='cross'):
        """Returns the fraction of data points in the integration that
        are exactly zero (generally this means they have been flagged
        or otherwise not recorded by the online systems).

        Note that for WIDAR autocorrelation data, the default is to only
        record half the antennas so will typically have ~50% zeros
        according to this function."""
        if type[0].lower()=='c':
            loc = 'crossData'
        elif type[0].lower()=='a':
            loc = 'autoData'
        if spwidx=='all':
            dtmp = self.data[loc].ravel()
        else:
            dtmp = self.get_data(spwidx=spwidx,type=type).ravel()
        return float(len(dtmp) - numpy.count_nonzero(dtmp))/float(len(dtmp))

class BDFWriter(object):
    """
    Write a BDF file.
    """
    def __init__(self, fname, bdf=None):
        """Init BDFWrite with output filename (fname).  If the bdf
        argument contains a BDF object, its header is copied for the
        output file.  Otherwise the BDFWrite.sdmDataHeader needs to
        be populated."""
        self.fname = fname
        self.fp = None
        self.curidx = 1
        self.mb1 = "MIME_boundary-1"
        self.mb2 = "MIME_boundary-2"
        self.len0 = 0
        self.len1 = 0
        self.len2 = 0
        self.sdmDataHeader = None
        if bdf is not None:
            self.sdmDataHeader = deepcopy(bdf.sdmDataHeader)

    def write_header(self):
        """Open output and write the current header contents."""
        self.fp = open(self.fname,'w')
        tophdr = MIMEHeader()
        tophdr['MIME-Version'] = ['1.0',]
        tophdr['Content-Type'] = ['multipart/mixed', 'boundary='+self.mb1]
        tophdr['Content-Description'] = [
                'EVLA/CORRELATOR/WIDAR/FULL_RESOLUTION',]
        # How do we generate a new unique name?
        nsxl = self.sdmDataHeader.nsmap['xl']
        uid = self.sdmDataHeader.dataOID.attrib['{%s}href'%nsxl][5:]
        tophdr['Content-Location'] = ['http://evla.nrao.edu/wcbe/XSDM' + uid,]
        self.fp.write(tophdr.tostring() + '\n')

        self.fp.write('--' + self.mb1 + '\n')
        xhdr = MIMEHeader()
        xhdr['Content-Type'] = ['text/xml', 'charset=utf-8']
        xhdr['Content-Location'] = ['sdmDataHeader.xml',]
        self.fp.write(xhdr.tostring() + '\n')
        self.fp.write(etree.tostring(self.sdmDataHeader,
            standalone=True,encoding='utf-8') + '\n')

    def write_integration(self,bdf_int):
        """Input is a BDFIntegration object.  The projectPath will be updated
        so that it is consistent for the file being written but otherwise
        no changes are made to the contents."""
        tophdr = MIMEHeader()
        tophdr['Content-Type'] = ['multipart/related', 'boundary='+self.mb2]
        tophdr['Content-Description'] = ['data and metadata subset',]

        ppidx = self.sdmDataHeader.attrib['projectPath'] + '%d/' % self.curidx

        hdr = MIMEHeader()
        hdr['Content-Type'] = ['text/xml', 'charset=utf-8']
        hdr['Content-Location'] = [ppidx + 'desc.xml']
        if self.len0==0:
            self.len0 = len(hdr.tostring()) + 12
        nxpad = self.len0 - len(hdr.tostring())
        if nxpad<0:
            raise RuntimeError('nxpad(0)<0')
        hdr['X-pad'] = ['*'*nxpad,]

        # Update subhdr with new path
        subhdr = deepcopy(bdf_int.sdmDataSubsetHeader)
        subhdr.attrib['projectPath'] = ppidx
        nsxl = subhdr.nsmap['xl']
        dtypes = []
        mhdr = {}
        for dtype in ('crossData', 'autoData'):
            try:
                loc = ppidx + dtype + '.bin'
                getattr(subhdr,dtype).attrib['{%s}href'%nsxl] = loc
                dtypes += [dtype,]
                mhdr[dtype] = MIMEHeader()
                mhdr[dtype]['Content-Type'] = ['application/octet-stream']
                mhdr[dtype]['Content-Location'] = [loc]
            except AttributeError:
                pass

        # Figure out how much X-pad to add
        subhdr_str = etree.tostring(subhdr, standalone=True, encoding='utf-8')
        if self.len1==0:
            self.len1 = len(subhdr_str) + len(mhdr[dtypes[0]].tostring()) + 50
        nxpad = self.len1 - (len(subhdr_str) + len(mhdr[dtypes[0]].tostring()))
        mhdr[dtypes[0]]['X-pad'] = ['*'*nxpad,]

        # Assumes at most 2 data types.. TODO make more general
        if len(dtypes)>1:
            if self.len2==0:
                self.len2 = len(mhdr[dtypes[1]].tostring()) + 12
            nxpad = self.len2 - len(mhdr[dtypes[1]].tostring())
            mhdr[dtypes[1]]['X-pad'] = ['*'*nxpad,]

        # TODO could check that data sizes match up with header info..

        # Now write it all out..
        self.fp.write('--' + self.mb1 + '\n')
        self.fp.write(tophdr.tostring()+'\n')

        # XML subheader part
        self.fp.write('--' + self.mb2 + '\n')
        self.fp.write(hdr.tostring() + '\n')
        self.fp.write(subhdr_str)

        # Data parts
        for dtype in dtypes:
            self.fp.write('\n--' + self.mb2 + '\n')
            self.fp.write(mhdr[dtype].tostring() + '\n')
            self.fp.write(bdf_int.data[dtype])

        # Close out mime
        self.fp.write('\n--' + self.mb2 + '--\n')
        self.curidx += 1

    def close(self):
        self.fp.write('--' + self.mb1 + '--\n')
        self.fp.close()


from django.template import Template, Context
from django.http import JsonResponse, HttpResponseBadRequest
from django.shortcuts import render
from django.views import View
from django.views.generic import ListView, FormView
from .models import (
    Project,
    Milestone,
    Module,
    Task,
    Comment,
)
from django.utils.translation import ugettext as _
from .forms import (
    AddTaskForm,
    AddModuleForm,
    AddMilestoneForm,
    AddProjectForm,
)

class ProjectListView(ListView):
    """
    Список проектов в которых участвует пользователь
    """
    template_name = 'project/projects.html'
    context_object_name = 'projects'
    model = Project

    def get(self, *args, **kwargs):
        last_visited_task = self.request.COOKIES.get('last_visited_task')

        if last_visited_task:
            try:
                task = Task.objects.get(id=last_visited_task)
            except Task.DoesNotExist:
                return super(ProjectListView, self).get(args, kwargs)

            module = task.module
            milestone = module.milestone
            project = milestone.project

            context = {
                'current_module': module,
                'modules': milestone.module_set.all(),
                'current_milestone': milestone,
                'milestones': project.milestone_set.all(),
                'current_task': task,
                'tasks': module.task_set.all(),
                'current_project': project,
                self.context_object_name: self.get_queryset(),
                'has_last_visited_task': True,
            }

            return render(self.request, self.template_name, context)

        return super(ProjectListView, self).get(args, kwargs)

class MilestonesLoaderView(View):

    def get(self, request, project_id):
        milestones = Milestone.objects.filter(project_id=project_id)

        context = {
            'milestones': milestones,
        }

        return render(request, 'project/_milestones-list.html', context)

class ModulesLoaderView(View):

    def get(self, request, milestone_id):
        modules = Module.objects.filter(milestone_id=milestone_id)

        context = {
            'modules': modules,
        }

        return render(request, 'project/_modules-list.html', context)

class TasksLoaderView(View):

    def get(self, request, module_id):
        tasks = Task.objects.filter(module_id=module_id)

        context = {
            'tasks': tasks,
        }

        return render(request, 'project/_tasks-list.html', context)

class SingleTaskLoaderView(View):

    def get(self, request, task_id):
        task = Task.objects.get(id=task_id)

        context = {
            'task': task,
        }

        return render(request, 'project/_task.html', context)

class AddCommentView(View):
    """
    Добавление коментария к задаче
    """

    def post(self, request, task_id):

        try:
            task = Task.objects.get(id=task_id)
        except Task.DoesNotExist:
            return HttpResponseBadRequest()

        comment_text = request.POST.get('comment_text')
        if len(comment_text) > 0:

            comment = Comment(
                text=comment_text,
                user=self.request.user,
                task=task,
            )
            comment.save()

            context = {
                'comment': comment,
            }

            return render(request, 'project/_comment.html', context)

        return JsonResponse({
            'status': 0,
            'message': _('Комментарий не может быть пустым')
        })

class AddTaskFormView(FormView):
    """
    Добавление задачи
    """
    template_name = 'project/_add-task-modal.html'
    form_class = AddTaskForm
    module_id = None

    def get(self, *args, **kwargs):
        self.module_id = self.request.GET.get('module_id')
        return super(AddTaskFormView, self).get(args, kwargs)

    def get_form_kwargs(self):
        kwargs = super(AddTaskFormView, self).get_form_kwargs()
        kwargs['module_id'] = self.module_id
        return kwargs

    def get_context_data(self, *args, **kwargs):
        context = super(AddTaskFormView, self).get_context_data()
        context['module_id'] = self.module_id
        return context

    def post(self, request, *args, **kwargs):

        module_id = request.POST.get('module')
        title = request.POST.get('title')
        description = request.POST.get('description')
        collaborator_id = request.POST.get('collaborator')
        time = request.POST.get('time')
        rate_per_hour = request.POST.get('rate_per_hour')
        status = request.POST.get('status')

        task = Task(
            module_id=module_id,
            title=title,
            description=description,
            collaborator_id=collaborator_id,
            time=time,
            rate_per_hour=rate_per_hour,
            status=status,
        )
        task.save()
        context = {
            'task': task,
        }

        t = Template("{% include 'project/_task-part.html' with task=task %}")
        template = t.render(Context(context))

        module = task.module
        milestone = module.milestone
        project = milestone.project

        return JsonResponse({
            'status': 1,
            'template': template,
            'percentages': {
                'project': project.get_percent(),
                'project_id': project.id,
                'milestone': milestone.get_percent(),
                'milestone_id': milestone.id,
                'module': module.get_percent(),
                'module_id': module.id,
            }
        })

        # return render(request, 'project/_task-part.html', context)

class AddModuleFormView(FormView):
    """
    Добавление модуля
    """
    template_name = 'project/_add-module-modal.html'
    form_class = AddModuleForm
    milestone_id = None

    def get(self, *args, **kwargs):
        self.milestone_id = self.request.GET.get('milestone_id')
        return super(AddModuleFormView, self).get(args, kwargs)

    def get_form_kwargs(self):
        kwargs = super(AddModuleFormView, self).get_form_kwargs()
        kwargs['milestone_id'] = self.milestone_id
        return kwargs

    def get_context_data(self, *args, **kwargs):
        context = super(AddModuleFormView, self).get_context_data()
        context['milestone_id'] = self.milestone_id
        return context

    def post(self, request, *args, **kwargs):

        milestone_id = request.POST.get('milestone')
        title = request.POST.get('title')
        description = request.POST.get('description')

        module = Module(
            milestone_id=milestone_id,
            title=title,
            description=description,
        )
        module.save()
        context = {
            'module': module,
        }

        t = Template("{% include 'project/_module-part.html' with module=module %}")
        template = t.render(Context(context))

        milestone = module.milestone
        project = milestone.project

        return JsonResponse({
            'status': 1,
            'template': template,
            'percentages': {
                'project': project.get_percent(),
                'project_id': project.id,
                'milestone': milestone.get_percent(),
                'milestone_id': milestone.id,
            }
        })

class AddMilestoneFormView(FormView):
    """
    Добавление майлстоуна
    """
    template_name = 'project/_add-milestone-modal.html'
    form_class = AddMilestoneForm
    project_id = None

    def get(self, *args, **kwargs):
        self.project_id = self.request.GET.get('project_id')
        return super(AddMilestoneFormView, self).get(args, kwargs)

    def get_form_kwargs(self):
        kwargs = super(AddMilestoneFormView, self).get_form_kwargs()
        kwargs['project_id'] = self.project_id
        return kwargs

    def get_context_data(self, *args, **kwargs):
        context = super(AddMilestoneFormView, self).get_context_data()
        context['project_id'] = self.project_id
        return context

    def post(self, request, *args, **kwargs):

        project_id = request.POST.get('project')
        index_number = request.POST.get('index_number')
        amount_of_days = request.POST.get('amount_of_days')
        date_start = request.POST.get('date_start')

        milestone = Milestone(
            project_id=project_id,
            index_number=index_number,
            amount_of_days=amount_of_days,
            date_start=date_start,
        )
        milestone.save()
        context = {
            'milestone': milestone,
        }

        t = Template("{% include 'project/_milestone-part.html' with milestone=milestone %}")
        template = t.render(Context(context))

        project = milestone.project

        return JsonResponse({
            'status': 1,
            'template': template,
            'percentages': {
                'project': project.get_percent(),
                'project_id': project.id,
            }
        })

class AddProjectFormView(FormView):
    """
    Добавление проекта
    """
    template_name = 'project/_add-project-modal.html'
    form_class = AddProjectForm

    def post(self, request, *args, **kwargs):

        title = request.POST.get('title')
        description = request.POST.get('description')
        client = request.POST.get('client')
        pm = request.POST.get('pm')
        status = request.POST.get('status')
        is_active = True if request.POST.get('is_active') == 'on' else False
        date_start = request.POST.get('date_start')
        date_end = request.POST.get('date_end')

        project = Project(
            title=title,
            description=description,
            client_id=client,
            pm_id=pm,
            status_id=status,
            is_active=is_active,
            date_start=date_start,
            date_end=date_end,
        )
        project.save()
        context = {
            'project': project,
        }

        t = Template("{% include 'project/_project-part.html' with project=project %}")
        template = t.render(Context(context))

        return JsonResponse({
            'status': 1,
            'template': template,
        })

class MakeTaskIsDoneView(View):

    def post(self, request):
        task_id = self.request.POST.get('task_id')

        if task_id:
            try:
                task = Task.objects.get(pk=task_id)
            except Task.DoesNotExist:
                context = {
                    'status': False,
                    'message': 'Такой задачи не существует'
                }
                return JsonResponse(context)

            task.status = 3
            task.save(update_fields=('status',))

            module = task.module
            milestone = module.milestone
            project = milestone.project

            context = {
                'status': True,
                'percentages': {
                    'project': project.get_percent(),
                    'project_id': project.id,
                    'milestone': milestone.get_percent(),
                    'milestone_id': milestone.id,
                    'module': module.get_percent(),
                    'module_id': module.id,
                }
            }
            return JsonResponse(context)

        context = {
            'status': False,
            'message': 'Oops!'
        }
        return JsonResponse(context)


import numpy as np
import sys
import pathlib

current_dir = pathlib.Path(__file__).resolve().parent
sys.path.append(str(current_dir) + "/../")
from common.physics_model import PhysicsModel

# state: (X, Y)
# X and Y are defined in inertial coordinate system.

# input: (x_velocity, y_velocity)
# The direction of x_force and y_force are defined in body coordinate system.

class Dot2D(PhysicsModel):
    def __init__(self, init_state, **kwargs):
        # set default param values
        self.name = "Dot2D"

        init_input = (0.0, 0.0)

        super().__init__(init_state, init_input, **kwargs)

    def dynamics(self, states, u):
        X_dot = u[0]
        Y_dot = u[1]

        return np.array([X_dot, Y_dot])

    def get_param(self):
        return {}

    def set_param(self, **kwargs):
        for key in kwargs:
            raise TypeError(
                "The required key {key!r} " "are not in kwargs".format(key=key)
            )

    def get_sensor_data(self):
        X_dot = self.last_state_dot[0]
        Y_dot = self.last_state_dot[1]
        return {"velocity": [X_dot, Y_dot]}


from pytest import approx

import numpy as np
import funcy as fn

from redax.module import Interface, CompositeInterface
from redax.spaces import DynamicCover
from redax.synthesis import ControlPre, DecompCPre, ReachGame, SafetyGame, ReachAvoidGame
from redax.visualizer import scatter2D, plot3D, plot3D_QT, pixel2D
from redax.utils.overapprox import bloatbox

from redax.predicates.dd import BDD
mgr = BDD()
mgr.configure(reordering=True)

ts = .2
k = .1
g = 9.8

def dynamics(p, v, a):
    vsign = 1 if v > 0 else -1
    return p + v * ts, v + a*ts - vsign*k*(v**2)*ts - g*ts

pspace = DynamicCover(-10, 10)
vspace = DynamicCover(-16, 16)
aspace = DynamicCover(0, 20)

# Smaller component modules
pcomp = Interface(mgr,
                 {'p': pspace,
                  'v': vspace},
                 {'pnext': pspace}
        )
vcomp = Interface(mgr,
                 {'v': vspace,
                  'a': aspace},
                 {'vnext': vspace}
        )

# Declare grid precision
p_precision = 7
v_precision = 7
precision = {'p': p_precision, 'v': v_precision, 'a': 7, 'pnext': p_precision, 'vnext': v_precision}
bittotal = sum(precision.values())
outorder = {0: 'pnext', 1: 'vnext'}
possible_transitions = (pcomp * vcomp).count_io_space(bittotal)

np.random.seed(1337)

for numapplied in range(6000):

    # Shrink window widths over time
    width = 20 * 1/np.log10(2*numapplied+10)

    # Generate random input windows
    f_width = {'p': np.random.rand()*.5*width,
               'v': np.random.rand()*width,
               'a': np.random.rand()*.5*width}
    f_left  = {'p': -10 +  np.random.rand() * (20 - f_width['p']),
               'v': -16 + np.random.rand() * (32 - f_width['v']),
               'a': 0 + np.random.rand() * (20 - f_width['a'])}
    f_right = {k: f_width[k] + f_left[k] for k in f_width}
    iobox   = {k: (f_left[k], f_right[k]) for k in f_width}

    # Generate output overapproximation
    ll = dynamics(**f_left)
    ur = dynamics(**f_right)
    outbox = {outorder[i]: (ll[i], ur[i]) for i in range(2)}
    iobox.update(outbox)

    # Apply constraint to parallel updates
    pcomp = pcomp.io_refined({k: v for k, v in iobox.items() if k in pcomp.vars}, nbits=precision)
    vcomp = vcomp.io_refined({k: v for k, v in iobox.items() if k in vcomp.vars}, nbits=precision)

def test_safe_control():
    composite = CompositeInterface((pcomp, vcomp))
    dcpre = DecompCPre(composite, (('p', 'pnext'), ('v', 'vnext')), ('a'))

    safe = pspace.conc2pred(mgr, 'p', [-8,8], 6, innerapprox=True)
    safesink = Interface(mgr, {'p': pspace, 'v': vspace}, {},  guar = mgr.true, assum=safe)

    # Solve game and plot 2D invariant region
    game = SafetyGame(dcpre, safesink)
    dinv, _, controller = game.run()

    system = pcomp * vcomp
    cpre = ControlPre(system, (('p', 'pnext'), ('v', 'vnext')), ('a'))
    game = SafetyGame(cpre, safesink)
    inv, _, _ = game.run(verbose=True)

    assert dinv == inv

#     assert dinv.count_nb(p_precision + v_precision) == approx(5988)

    # Simulate for initial states
    state_box = fn.first(controller.winning_states())
    assert state_box is not None
    state = {k: .5*(v[0] + v[1]) for k, v in state_box.items()}
    for step in range(30):
        u = fn.first(controller.allows(state))
        assert u is not None
        picked_u = {'a': u['a'][0]} # Pick lower bound of first allowed control voxel

        state.update(picked_u)
        nextstate = dynamics(**state)
        state = {'p': nextstate[0], 'v': nextstate[1]}

def test_reach_control():
    composite = CompositeInterface((pcomp, vcomp))
    dcpre = DecompCPre(composite, (('p', 'pnext'), ('v', 'vnext')), ('a'))

    target = pspace.conc2pred(mgr, 'p', [-2,2], 6, innerapprox=True)
    targetint = Interface(mgr, {'p': pspace, 'v': vspace}, {},  guar = mgr.true, assum=target)

    # Solve game and plot 2D invariant region
    game = ReachGame(dcpre, targetint)
    dbasin, _, _ = game.run()

    system = pcomp * vcomp
    cpre = ControlPre(system, (('p', 'pnext'), ('v', 'vnext')), ('a'))
    game = ReachGame(cpre, targetint)
    basin, _, _ = game.run()

    assert dbasin == basin

#     assert dbasin.count_nb(p_precision + v_precision) == approx(5964)

def test_reachavoid():
    composite = CompositeInterface((pcomp, vcomp))
    dcpre = DecompCPre(composite, (('p', 'pnext'), ('v', 'vnext')), ('a'))

    target =  pspace.conc2pred(mgr, 'p', [-3,3], 6, innerapprox=True)
    target &= vspace.conc2pred(mgr, 'v', [0,2], 6, innerapprox=True)
    targetint = Interface(mgr, {'p': pspace, 'v': vspace}, {},  guar = mgr.true, assum=target)

    safe =  pspace.conc2pred(mgr, 'p', [-8,8], 6, innerapprox=True)
    safe &=  ~pspace.conc2pred(mgr, 'p', [-.4,.4], 6, innerapprox=True)
    safe &= vspace.conc2pred(mgr, 'v', [-4,4], 6, innerapprox=True)
    safeint = Interface(mgr, {'p': pspace, 'v': vspace}, {},  guar = mgr.true, assum=safe)

    game = ReachAvoidGame(dcpre, safeint, targetint)
    basin, _, _ = game.run()

#     scatter2D(mgr, ('p', pspace), ('v', vspace),
#                  basin.pred,
#                  fname = "reachavoid_doubleint.png"
#                  )


from django.db import models

# Create your models here.

from django.db import models
from datetime import datetime
from ckeditor.fields import RichTextField
from multiselectfield import MultiSelectField

# Create your models here.
class Car(models.Model):

    city_choice = (
        ('Antipolo', 'Antipolo'),
        ('BGC', 'BGC'),
        ('Makati', 'Makati'),
        ('Marikina', 'Marikina'),
        ('Pasig', 'Pasig'),
        ('Quezon City', 'Quezon City'),
        ('San Juan', 'San Juan'),
        ('Taguig', 'Taguig'),
    )

    year_choice = []
    for r in range(2000, (datetime.now().year+1)):
        year_choice.append((r,r))

    features_choices = (
        ('Cruise Control', 'Cruise Control'),
        ('Audio Interface', 'Audio Interface'),
        ('Airbags', 'Airbags'),
        ('Air Conditioning', 'Air Conditioning'),
        ('Seat Heating', 'Seat Heating'),
        ('Alarm System', 'Alarm System'),
        ('ParkAssist', 'ParkAssist'),
        ('Power Steering', 'Power Steering'),
        ('Reversing Camera', 'Reversing Camera'),
        ('Direct Fuel Injection', 'Direct Fuel Injection'),
        ('Auto Start/Stop', 'Auto Start/Stop'),
        ('Wind Deflector', 'Wind Deflector'),
        ('Bluetooth Handset', 'Bluetooth Handset'),
    )

    door_choices = (
        ('2', '2'),
        ('3', '3'),
        ('4', '4'),
        ('5', '5'),
        ('6', '6'),
    )

    transmission_choices = (
        ('Automatic', 'Automatic'),
        ('Manual', 'Manual'),
        ('Hybrid', 'Hybrid'),
    )

    body_choices = (
        ('SUV', 'SUV'),
        ('Crossover', 'Crossover'),
        ('Sedan', 'Sedan'),
        ('Hatchback', 'Hatchback'),
        ('Coupe', 'Coupe'),
        ('Convertible', 'Convertible'),
        ('Sports', 'Sports'),
        ('Truck', 'Truck'),
        ('Van', 'Van'),
    )

    passengers_choices = (
        ('2', '2'),
        ('4', '4'),
        ('6', '6'),
        ('8', '8'),
        ('10', '10'),
        ('12', '12'),
    )

    fuel_choices = (
        ('Gasoline', 'Gasoline'),
        ('Diesel', 'Diesel'),
        ('Bio-diesel', 'Bio-diesel'),
        ('Ethanol', 'Ethanol'),
    )

    car_title = models.CharField(max_length=255)
    city = models.CharField(choices=city_choice, max_length=100)
    color = models.CharField(max_length=100)
    model = models.CharField(max_length=100)
    year = models.IntegerField(('year'), choices=year_choice)
    condition = models.CharField(max_length=100)
    price = models.IntegerField()
    description = RichTextField()
    car_photo = models.ImageField(upload_to='photos/%Y/%m/%d/')
    car_photo_1 = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
    car_photo_2 = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
    car_photo_3 = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
    car_photo_4 = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
    features = MultiSelectField(choices=features_choices)
    body_style = models.CharField(choices=body_choices, max_length=100)
    engine = models.CharField(max_length=100)
    transmission = models.CharField(choices=transmission_choices, max_length=50)
    interior = models.CharField(max_length=100)
    miles = models.IntegerField()
    doors = models.CharField(choices=door_choices, max_length=10)
    passengers = models.CharField(choices=passengers_choices, max_length=10)
    vin_no = models.CharField(max_length=100)
    milage = models.IntegerField()
    fuel_type = models.CharField(choices=fuel_choices, max_length=50)
    no_of_owners = models.CharField(max_length=100)
    is_featured = models.BooleanField(default=False)
    created_date = models.DateTimeField(default=datetime.now, blank=True)

    def __str__(self):
        return self.car_title


import telebot
from config import keys, TOKEN
from extensions import CryptoConverter, ConvertionException

bot = telebot.TeleBot(TOKEN)

@bot.message_handler(commands=['start', 'help'])
def hepl(message: telebot.types.Message):
    text = "Чтобы начать работу введите команду боту в следующем формате: \n <имя валюты цену которой хотите узнать> \
    <имя валюты в которой надо узнать цену первой валюты> \
    <количество первой валюты> \n Увидеть список всех возможных влют: /values"
    bot.reply_to(message, text)

@bot.message_handler(commands=['values'])
def values(message: telebot.types.Message):
    text = "Доступные валюты"
    for key in keys.keys():
        text = '\n'.join((text, key, ))
    bot.reply_to(message, text)

@bot.message_handler(content_types=['text',])
def convert(message: telebot.types.Message):
    try:
        values = message.text.split(' ')

        if len(values) != 3:
            raise ConvertionException("Запрос введен некорректно. Слишком много/мало параметров.")
        quote, base, amount = values
        quote = quote.upper()
        base = base.upper()
        amount = amount.replace(",", ".")
        cost = CryptoConverter.convert(quote, base, amount)
    except ConvertionException as e:
        bot.reply_to(message, f"Ошибка пользователя. \n {e}")
    except Exception as e:
        bot.reply_to(message, f"Не удалось обработать команду. \n {e}")
    else:
        text = f"Цена 1 {quote} - {cost.get('single')} {base}.\n Стоимость {amount} {quote} = {cost.get('total')} {base}"
        bot.send_message(message.chat.id, text)

bot.polling()