import datetime
import os
import sys
import mimetypes
from dateutil.relativedelta import relativedelta
from wsgiref.util import FileWrapper
from typing import Dict

from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError, SuspiciousOperation
from django.db import OperationalError, ProgrammingError
from django.db.models import Q
from django.http import JsonResponse, HttpResponse, HttpRequest, HttpResponseForbidden
from django.shortcuts import render, redirect, get_object_or_404, \
    render_to_response
from django.urls import reverse

from .forms import ArticleForm, UserProfileForm, UserForm, WorkshopForm, \
    UserProfilePageForm, WorkshopPageForm, UserCoverLetterForm, UserInfoPageForm
from .models import Article, UserProfile, Workshop, WorkshopParticipant, \
    WorkshopUserProfile, ResourceYearPermission
from .templatetags.wwwtags import qualified_mark

def get_context(request):
    context = {}

    context['has_workshops'] = False

    if request.user.is_authenticated:
        if Workshop.objects.filter(lecturer__user=request.user).exists():
            context['has_workshops'] = True

        visible_resources = ResourceYearPermission.objects.exclude(access_url__exact="")
        if request.user.has_perm('wwwapp.access_all_resources'):
            context['resources'] = visible_resources
        else:
            try:
                user_profile = UserProfile.objects.get(user=request.user)
                context['resources'] = visible_resources.filter(year__in=user_profile.all_participation_years())
            except UserProfile.DoesNotExist:
                context['resources'] = []

    context['google_analytics_key'] = settings.GOOGLE_ANALYTICS_KEY
    context['articles_on_menubar'] = Article.objects.filter(on_menubar=True).all()
    context['current_year'] = settings.CURRENT_YEAR

    return context

def program_view(request, year):
    context = get_context(request)
    context['title'] = 'Program WWW%d' % (int(year) % 100 - 4)  # :)

    if request.user.is_authenticated:
        user_participation = set(Workshop.objects.filter(participants__user=request.user).all())
    else:
        user_participation = set()

    workshops = Workshop.objects.filter(Q(status='Z') | Q(status='X'), type__year=year).order_by('title').prefetch_related('lecturer', 'lecturer__user', 'category')
    context['workshops'] = [(workshop, (workshop in user_participation)) for workshop
                            in workshops]

    if request.user.is_authenticated:
        qualifications = WorkshopParticipant.objects.filter(participant__user=request.user, workshop__type__year=year).prefetch_related('workshop')
        if not any(qualification.qualification_result is not None for qualification in qualifications):
            qualifications = None
        context['your_qualifications'] = qualifications

    return render(request, 'program.html', context)

def profile_view(request, user_id):
    """
    This function allows to view other people's profile by id.
    However, to view them easily some kind of resolver might be needed as we don't have usernames.
    """
    context = get_context(request)
    user_id = int(user_id)
    user = get_object_or_404(User, pk=user_id)

    profile = UserProfile.objects.get(user=user)
    profile_page = profile.profile_page

    is_my_profile = (request.user == user)
    can_see_all_users = request.user.has_perm('wwwapp.see_all_users')
    can_see_all_workshops = request.user.has_perm('wwwapp.see_all_workshops')

    context['title'] = "{0.first_name} {0.last_name}".format(user)
    context['profile_page'] = profile_page
    context['is_my_profile'] = is_my_profile
    context['gender'] = profile.gender

    if can_see_all_users or is_my_profile:
        context['profile'] = profile
        context['participation_data'] = profile.all_participation_data()
        if not can_see_all_workshops and not is_my_profile:
            # If the current user can't see non-public workshops, remove them from the list
            for participation in context['participation_data']:
                participation['workshops'] = [w for w in participation['workshops'] if w.is_publicly_visible()]

    if can_see_all_workshops or is_my_profile:
        context['lecturer_workshops'] = profile.lecturer_workshops.all().order_by('type__year')
    else:
        context['lecturer_workshops'] = profile.lecturer_workshops.filter(Q(status='Z') | Q(status='X')).order_by('type__year')
    context['can_see_all_workshops'] = can_see_all_workshops

    can_qualify = request.user.has_perm('wwwapp.change_workshop_user_profile')
    context['can_qualify'] = can_qualify
    context['has_workshop_profile'] = WorkshopUserProfile.objects.filter(
        user_profile=user.userprofile, year=settings.CURRENT_YEAR).exists()

    if request.method == 'POST':
        if not can_qualify:
            return HttpResponseForbidden()
        (edition_profile, _) = WorkshopUserProfile.objects.get_or_create(
            user_profile=user.userprofile, year=settings.CURRENT_YEAR)
        context['has_workshop_profile'] = True
        if request.POST['qualify'] == 'accept':
            edition_profile.status = WorkshopUserProfile.STATUS_ACCEPTED
            edition_profile.save()
        elif request.POST['qualify'] == 'reject':
            edition_profile.status = WorkshopUserProfile.STATUS_REJECTED
            edition_profile.save()
        elif request.POST['qualify'] == 'delete':
            edition_profile.delete()
            context['has_workshop_profile'] = False
        else:
            raise SuspiciousOperation("Invalid argument")

    return render(request, 'profile.html', context)

@login_required()
def my_profile_view(request):
    context = get_context(request)
    user_profile = UserProfile.objects.get(user=request.user)

    user_form = UserForm(instance=request.user)
    user_profile_form = UserProfileForm(instance=user_profile)
    user_profile_page_form = UserProfilePageForm(instance=user_profile)
    user_cover_letter_form = UserCoverLetterForm(instance=user_profile)
    user_info_page_form = UserInfoPageForm(instance=user_profile.user_info)

    if request.method == "POST":
        page = request.POST['page']
        if page == 'data':
            user_form = UserForm(request.POST, instance=request.user)
            user_profile_form = UserProfileForm(request.POST, instance=user_profile)
            if user_form.is_valid() and user_profile_form.is_valid():
                user_form.save()
                user_profile_form.save()
                messages.info(request, 'Zapisano.')
        elif page == 'profile_page':
            user_profile_page_form = UserProfilePageForm(request.POST, instance=user_profile)
            if user_profile_page_form.is_valid():
                user_profile_page_form.save()
                messages.info(request, 'Zapisano.')
        elif page == 'cover_letter':
            user_cover_letter_form = UserCoverLetterForm(request.POST, instance=user_profile)
            if user_cover_letter_form.is_valid():
                user_cover_letter_form.save()
                messages.info(request, 'Zapisano.')
        elif page == 'user_info':
            user_info_page_form = UserInfoPageForm(request.POST, instance=user_profile.user_info)
            if user_info_page_form.is_valid():
                user_info_page_form.save()
                messages.info(request, 'Zapisano.')
        else:
            raise SuspiciousOperation('Invalid page')

    user_form.helper.form_tag = False
    user_profile_form.helper.form_tag = False
    context['user_form'] = user_form
    context['user_profile_form'] = user_profile_form
    context['user_profile_page_form'] = user_profile_page_form
    context['user_cover_letter_form'] = user_cover_letter_form
    context['user_info_page_form'] = user_info_page_form
    context['is_editing_profile'] = True
    context['title'] = 'Mój profil'

    return render(request, 'profile.html', context)

def workshop_view(request, name=None):
    new = (name is None)
    if new:
        workshop = None
        title = 'Nowe warsztaty'
        if not request.user.is_authenticated:
            return redirect('login')
        else:
            has_perm_to_edit = True
    else:
        workshop = Workshop.objects.get(name=name)
        title = workshop.title
        if request.user.is_authenticated:
            has_perm_to_edit = Workshop.objects.filter(name=name, lecturer__user=request.user).exists()
        else:
            has_perm_to_edit = False

    # Workshop proposals are only visible to admins
    has_perm_to_see_all = request.user.has_perm('wwwapp.see_all_workshops')
    if not has_perm_to_edit and not has_perm_to_see_all:
        return redirect('login')

    if has_perm_to_edit:
        if request.method == 'POST':
            form = WorkshopForm(request.POST, instance=workshop)
            if form.is_valid():
                workshop = form.save(commit=False)
                workshop.save()
                form.save_m2m()
                user_profile = UserProfile.objects.get(user=request.user)
                workshop.lecturer.add(user_profile)
                workshop.save()
                messages.info(request, 'Zapisano.')
                return redirect('workshop', form.instance.name)
        else:
            form = WorkshopForm(instance=workshop)
    else:
        form = None

    context = get_context(request)
    context['title'] = title
    context['workshop'] = workshop
    context['has_perm_to_edit'] = has_perm_to_edit
    context['has_perm_to_view_details'] = has_perm_to_edit or has_perm_to_see_all

    context['form'] = form

    return render(request, 'workshop.html', context)

def can_edit_workshop(workshop, user):
    if user.is_authenticated:
        return Workshop.objects.filter(id=workshop.id, lecturer__user=user).exists()
    else:
        return False

def workshop_page_view(request, name):
    workshop = get_object_or_404(Workshop, name=name)
    has_perm_to_edit = can_edit_workshop(workshop, request.user)

    if not workshop.is_publicly_visible():  # Accepted or cancelled
        return HttpResponseForbidden("Warsztaty nie zostały zaakceptowane")

    context = get_context(request)
    context['workshop'] = workshop
    context['has_perm_to_edit'] = has_perm_to_edit
    context['has_perm_to_view_details'] = \
        has_perm_to_edit or request.user.has_perm('wwwapp.see_all_workshops')

    return render(request, 'workshoppage.html', context)

def workshop_page_edit_view(request, name):
    workshop = get_object_or_404(Workshop, name=name)

    if not workshop.is_publicly_visible():  # Accepted or cancelled
        return HttpResponseForbidden("Warsztaty nie zostały zaakceptowane")
    if not can_edit_workshop(workshop, request.user):
        return HttpResponseForbidden()

    if request.method == 'POST':
        form = WorkshopPageForm(request.POST, request.FILES,
                                instance=workshop)
        if form.is_valid():
            workshop = form.save(commit=False)
            workshop.save()
            form.save_m2m()
            user_profile = UserProfile.objects.get(user=request.user)
            workshop.lecturer.add(user_profile)
            workshop.save()
            messages.info(request, 'Zapisano.')
            return redirect('workshop_page_edit', form.instance.name)
    else:
        if not workshop.page_content:
            workshop_template = Article.objects.get(
                name="template_for_workshop_page").content
            workshop.page_content = workshop_template
            workshop.save()
        form = WorkshopPageForm(instance=workshop)

    context = get_context(request)
    context['workshop'] = workshop
    context['has_perm_to_edit'] = True
    context['has_perm_to_view_details'] = True

    context['form'] = form

    return render(request, 'workshoppage.html', context)

@login_required()
def workshop_participants_view(request, name):
    workshop = get_object_or_404(Workshop, name=name)
    has_perm_to_edit = can_edit_workshop(workshop, request.user)

    if not workshop.is_publicly_visible():  # Accepted or cancelled
        return HttpResponseForbidden("Warsztaty nie zostały zaakceptowane")

    if not (has_perm_to_edit or request.user.has_perm('wwwapp.see_all_workshops')):
        return HttpResponseForbidden()

    context = get_context(request)
    context['workshop'] = workshop
    context['has_perm_to_edit'] = has_perm_to_edit
    context['has_perm_to_view_details'] = True

    context['workshop_participants'] = WorkshopParticipant.objects.filter(workshop=workshop).prefetch_related(
            'workshop', 'participant', 'participant__user')

    return render(request, 'workshopparticipants.html', context)

def save_points_view(request):
    workshop_participant = WorkshopParticipant.objects.get(id=request.POST['id'])

    can_edit = can_edit_workshop(workshop_participant.workshop, request.user)
    if not can_edit:
        return JsonResponse({'error': 'Brak uprawnień.'})

    try:
        result_points = (request.POST['points'].strip() if 'points' in request.POST else None)
        result_comment = (request.POST['comment'].strip() if 'comment' in request.POST else None)
        if result_points is not None:
            if result_points == "":
                workshop_participant.qualification_result = None
            else:
                workshop_participant.qualification_result = result_points
        if result_comment is not None:
            workshop_participant.comment = result_comment
        workshop_participant.save()
    except (ValidationError, ValueError) as e:
        print(e)
        return JsonResponse({'error': 'Niepoprawny format liczby'})
    except Exception as e:
        print(e)
        raise e
    workshop_participant = WorkshopParticipant.objects.get(id=workshop_participant.id)

    return JsonResponse({'points': str(workshop_participant.qualification_result),
                         'comment': workshop_participant.comment,
                         'mark': qualified_mark(workshop_participant.is_qualified())})

@login_required()
@permission_required('wwwapp.see_all_workshops', raise_exception=True)
def participants_view(request, year):
    year = int(year)

    participants = WorkshopParticipant.objects.all().filter(workshop__type__year=year)\
                                                    .prefetch_related('workshop', 'participant', 'participant__user')
    workshops = Workshop.objects.filter(type__year=year).prefetch_related('lecturer', 'lecturer__user')
    lecturers_ids = set()
    for workshop in workshops:
        for l in workshop.lecturer.all():
            lecturers_ids.add(l.user.id)

    people = {}

    for participant in participants:
        p_id = participant.participant.id
        if p_id not in people:
            cover_letter = participant.participant.cover_letter
            if participant.participant.user.id in lecturers_ids:
                continue

            birth = participant.participant.user_info.get_birth_date()
            is_adult = None
            if birth is not None:
                is_adult = settings.WORKSHOPS_START_DATE >= birth + relativedelta(years=18)

            people[p_id] = {
                'user': participant.participant.user,
                'birth': birth,
                'is_adult': is_adult,
                'pesel': participant.participant.user_info.pesel,
                'address': participant.participant.user_info.address,
                'phone': participant.participant.user_info.phone,
                'tshirt_size': participant.participant.user_info.tshirt_size,
                'matura_exam_year': participant.participant.matura_exam_year,
                'accepted_workshop_count': 0,
                'workshop_count': 0,
                'has_letter': bool(cover_letter and len(cover_letter) > 50),
                'status': participant.participant.status_for(year),
                'school': participant.participant.school,
                'points': 0.0,
                'infos': [],
                'comments': participant.participant.user_info.comments,
                'start_date': participant.participant.user_info.start_date,
                'end_date': participant.participant.user_info.end_date,
            }

        if participant.qualification_result:
            people[p_id]['points'] += float(participant.result_in_percent())
        people[p_id]['infos'].append("{title} : {result:.1f}% : {comment}".format(
            title=participant.workshop.title,
            result=participant.result_in_percent() if participant.qualification_result else 0,
            comment=participant.comment if participant.comment else ""
        ))
        people[p_id]['workshop_count'] += 1
        if participant.is_qualified():
            people[p_id]['accepted_workshop_count'] += 1

    people = list(people.values())

    context = get_context(request)
    context['title'] = 'Uczestnicy'
    context['people'] = people

    return render(request, 'participants.html', context)

@login_required()
@permission_required('wwwapp.see_all_workshops', raise_exception=True)
def lecturers_view(request: HttpRequest, year: int) -> HttpResponse:
    year = int(year)

    workshops = Workshop.objects.filter(type__year=year, status=Workshop.STATUS_ACCEPTED).prefetch_related('lecturer', 'lecturer__user')

    people: Dict[int, Dict[str, any]] = {}
    for workshop in workshops:
        for lecturer in workshop.lecturer.all():
            if lecturer.id in people:
                people[lecturer.id]['workshops'].append(workshop.info_for_client_link())
                continue

            birth = lecturer.user_info.get_birth_date()
            is_adult = None
            if birth is not None:
                is_adult = settings.WORKSHOPS_START_DATE >= birth + relativedelta(years=18)

            people[lecturer.id] = {
                'user': lecturer.user,
                'birth': birth,
                'is_adult': is_adult,
                'pesel': lecturer.user_info.pesel,
                'address': lecturer.user_info.address,
                'phone': lecturer.user_info.phone,
                'tshirt_size': lecturer.user_info.tshirt_size,
                'comments': lecturer.user_info.comments,
                'start_date': lecturer.user_info.start_date,
                'end_date': lecturer.user_info.end_date,
                'workshops': [workshop.info_for_client_link()],
            }

    people_list = list(people.values())

    context = get_context(request)
    context['title'] = 'Prowadzący'
    context['people'] = people_list

    return render(request, 'lecturers.html', context)

def register_to_workshop_view(request):
    workshop_name = request.POST['workshop_name']

    if not request.user.is_authenticated:
        return JsonResponse({'redirect': reverse('login'), 'error': u'Jesteś niezalogowany'})

    workshop = get_object_or_404(Workshop, name=workshop_name)

    if workshop.type.year != settings.CURRENT_YEAR:
        return JsonResponse({'error': 'Kwalifikacja na te warsztaty została dawno zakończona.'})

    if datetime.datetime.now().date() >= settings.WORKSHOPS_START_DATE:
        return JsonResponse({'error': u'Kwalifikacja na te warsztaty została zakończona.'})

    WorkshopParticipant(participant=UserProfile.objects.get(user=request.user), workshop=workshop).save()

    context = get_context(request)
    context['workshop'] = workshop
    context['registered'] = True
    return JsonResponse({'content': render_to_response('_programworkshop.html', context).content.decode()})

def unregister_from_workshop_view(request):
    workshop_name = request.POST['workshop_name']
    data = {}
    if not request.user.is_authenticated:
        return JsonResponse({'redirect': reverse('login'), 'error': u'Jesteś niezalogowany'})

    workshop = get_object_or_404(Workshop, name=workshop_name)
    profile = UserProfile.objects.get(user=request.user)
    workshop_participant = WorkshopParticipant.objects.get(workshop=workshop, participant=profile)

    if workshop.type.year != settings.CURRENT_YEAR:
        return JsonResponse({'error': 'Kwalifikacja na te warsztaty została dawno zakończona.'})

    if datetime.datetime.now().date() >= settings.WORKSHOPS_START_DATE:
        return JsonResponse({'error': u'Kwalifikacja na te warsztaty została zakończona.'})

    if workshop_participant.qualification_result is not None or workshop_participant.comment:
        return JsonResponse({'error': u'Masz już wyniki z tej kwalifikacji - nie możesz się wycofać.'})

    workshop_participant.delete()

    context = get_context(request)
    context['workshop'] = workshop
    context['registered'] = False
    data['content'] = render_to_response('_programworkshop.html', context).content.decode()
    return JsonResponse(data)

@permission_required('wwwapp.export_workshop_registration')
def data_for_plan_view(request):
    data = {}

    participant_profiles_raw = UserProfile.objects.filter(workshop_profile__year=settings.CURRENT_YEAR, workshop_profile__status='Z')

    lecturer_profiles_raw = set()
    workshop_ids = set()
    workshops = []
    for workshop in Workshop.objects.filter(status='Z', type__year=settings.CURRENT_YEAR):
        workshop_data = {'wid': workshop.id,
                         'name': workshop.title,
                         'lecturers': [lect.id for lect in
                                       workshop.lecturer.all()]}
        for lecturer in workshop.lecturer.all():
            if lecturer not in participant_profiles_raw:
                lecturer_profiles_raw.add(lecturer)
        workshop_ids.add(workshop.id)
        workshops.append(workshop_data)
    data['workshops'] = workshops

    users = []
    user_ids = set()

    for user_type, profiles in [('Lecturer', lecturer_profiles_raw),
                                ('Participant', participant_profiles_raw)]:
        for up in profiles:
            users.append({
                'uid': up.id,
                'name': up.user.get_full_name(),
                'type': user_type,
                'start': up.user_info.start_date if up.user_info.start_date != 'no_idea' else 1,
                'end': up.user_info.end_date if up.user_info.end_date != 'no_idea' else 30
            })
            user_ids.add(up.id)

    data['users'] = users

    participation = []
    for wp in WorkshopParticipant.objects.all():
        if wp.workshop.id in workshop_ids and wp.participant.id in user_ids:
            participation.append({
                'wid': wp.workshop.id,
                'uid': wp.participant.id,
            })
    data['participation'] = participation

    return JsonResponse(data, json_dumps_params={'indent': 4})

def qualification_problems_view(request, workshop_name):
    workshop = get_object_or_404(Workshop, name=workshop_name)
    filename = workshop.qualification_problems.path

    wrapper = FileWrapper(open(filename, "rb"))
    response = HttpResponse(wrapper, content_type=mimetypes.guess_type(filename)[0])
    response['Content-Length'] = os.path.getsize(filename)
    return response

def article_view(request, name=None):
    context = get_context(request)
    new = (name is None)
    if new:
        art = None
        title = 'Nowy artykuł'
        has_perm = request.user.has_perm('wwwapp.add_article')
    else:
        art = Article.objects.get(name=name)
        title = art.title
        has_perm = request.user.has_perm('wwwapp.change_article')

    if has_perm:
        if request.method == 'POST':
            form = ArticleForm(request.user, request.POST, instance=art)
            if form.is_valid():
                article = form.save(commit=False)
                article.modified_by = request.user
                article.save()
                form.save_m2m()
                messages.info(request, 'Zapisano.')
                return redirect('article', form.instance.name)
        else:
            form = ArticleForm(request.user, instance=art)
    else:
        form = None

    context['addArticle'] = new
    context['title'] = title
    context['article'] = art
    context['form'] = form

    return render(request, 'article.html', context)

def article_name_list_view(request):
    names = Article.objects.values_list('name', flat=True)
    return JsonResponse(list(names), safe=False)

@login_required()
def your_workshops_view(request):
    workshops = Workshop.objects.filter(lecturer__user=request.user)
    return render_workshops(request, 'Twoje warsztaty', True, workshops)

@login_required()
@permission_required('wwwapp.see_all_workshops', raise_exception=True)
def all_workshops_view(request):
    workshops = Workshop.objects.all()
    return render_workshops(request, 'Wszystkie warsztaty', False, workshops)

def render_workshops(request, title, link_to_edit, workshops):
    context = get_context(request)

    years = set(workshop.type.year for workshop in workshops)
    years = list(reversed(sorted(years)))
    context['workshops'] = [
        {'year': year,
         'workshops': [workshop for workshop in workshops if workshop.type.year == year]}
        for year in years]
    context['title'] = title
    context['link_to_edit'] = link_to_edit

    return render(request, 'workshoplist.html', context)

@login_required()
@permission_required('wwwapp.see_all_workshops', raise_exception=True)  # Think about seperate permission
def emails_view(request):
    workshops = Workshop.objects.all()

    result = []
    for workshop in workshops:
        lecturer = workshop.lecturer.all()[0]
        email = lecturer.user.email
        name = lecturer.user.first_name + " " + lecturer.user.last_name

        to_append = {'workshopname': workshop.title, 'email': email, 'name': name}
        result.append(to_append)

    return JsonResponse(result, safe=False)

def as_article(name):
    # We want to make sure that article with this name exists.
    # try-except is needed because of some migration/initialization problems.
    try:
        Article.objects.get_or_create(name=name)
    except OperationalError:
        print("WARNING: Couldn't create article named", name,
              "; This should happen only during migration.", file=sys.stderr)
    except ProgrammingError:
        print("WARNING: Couldn't create article named", name,
              "; This should happen only during migration.", file=sys.stderr)

    def page(request):
        return article_view(request, name)
    return page

index_view = as_article("index")
template_for_workshop_page_view = as_article("template_for_workshop_page")

def resource_auth_view(request):
    """
    View checking permission for resource (header X-Original-URI). Returns 200
    when currently logged in user should be granted access to resource and 403
    when access should be denied.

    See https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-subrequest-authentication/
    for intended usage.
    """
    if not request.user.is_authenticated:
        return HttpResponseForbidden("You need to login.")
    if request.user.has_perm('wwwapp.access_all_resources'):
        return HttpResponse("Glory to WWW and the ELITARNY MIMUW!!!")

    user_profile = UserProfile.objects.get(user=request.user)

    uri = request.META.get('HTTP_X_ORIGINAL_URI', '')

    for resource in ResourceYearPermission.resources_for_uri(uri):
        if user_profile.is_participating_in(resource.year):
            return HttpResponse("Welcome!")
    return HttpResponseForbidden("What about NO!")


from functools import reduce
from operator import mul

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable

class MetaOptimizer(nn.Module):

    def __init__(self, hidden_size):
        super(MetaOptimizer, self).__init__()
        self.hidden_size = hidden_size

        self.linear1 = nn.Linear(1, hidden_size)

        self.lstm = nn.LSTMCell(hidden_size, hidden_size)

        self.linear2 = nn.Linear(hidden_size, 1)
        self.linear2.weight.data.mul_(0.1)
        self.linear2.bias.data.fill_(0.0)

        self.reset_lstm()

    def reset_lstm(self):
        self.hx = Variable(torch.zeros(1, self.hidden_size))
        self.cx = Variable(torch.zeros(1, self.hidden_size))

    def forward(self, inputs):
        initial_size = inputs.size()
        x = inputs.view(-1, 1)
        x = F.tanh(self.linear1(x))

        if x.size(0) != self.hx.size(0):
            self.hx = self.hx.expand(x.size(0), self.hx.size(1))
            self.cx = self.hx.expand(x.size(0), self.cx.size(1))

        self.hx, self.cx = self.lstm(x, (self.hx, self.cx))
        x = self.hx

        x = self.linear2(x)
        x = x.view(*initial_size)
        return x

    def meta_update(self, meta_model, model_with_grads):
        # First we need to create a flat version of parameters and gradients
        weight_shapes = []
        bias_shapes = []

        params = []
        grads = []

        for module in meta_model.children():
            weight_shapes.append(list(module._parameters['weight'].size()))
            bias_shapes.append(list(module._parameters['bias'].size()))

            params.append(module._parameters['weight'].view(-1))
            params.append(module._parameters['bias'].view(-1))

        for module in model_with_grads.children():
            grads.append(module._parameters['weight'].grad.view(-1))
            grads.append(module._parameters['bias'].grad.view(-1))

        flat_params = torch.cat(params)
        flat_grads = torch.cat(grads)

        # Meta update itself
        flat_params = flat_params + self(flat_grads)

        # Restore original shapes
        offset = 0
        for i, module in enumerate(meta_model.children()):
            weight_flat_size = reduce(mul, weight_shapes[i], 1)
            bias_flat_size = reduce(mul, bias_shapes[i], 1)

            module._parameters['weight'] = flat_params[
                offset:offset + weight_flat_size].view(*weight_shapes[i])
            module._parameters['bias'] = flat_params[
                offset + weight_flat_size:offset + weight_flat_size + bias_flat_size].view(*bias_shapes[i])

            offset += weight_flat_size + bias_flat_size

        # Finally, copy values from the meta model to the normal one.
        meta_model.copy_params_to(model_with_grads)


import datetime

from flask_restplus import Namespace, Resource

from utils import brl_format, percentage_format
from stock_models.models.daily_quote_holder import DailyQuoteHolder
from stock_models.models.fund_daily_values import DailyFund
from stock_models.models.quote_holder import QuoteHolderMovements
from stock_models.models.yahoo_ticker_value import YahooTickerValue
from stock_models.utils.io_utils import session

dashboard_ns = Namespace("dashboard")

@dashboard_ns.route("/")
class Dashboard(Resource):
    def get(self):
        graph = {'labels': [], 'series': [[], []]}
        all_fund = session().query(DailyFund).order_by(DailyFund.ref_date.asc()).all()
        first = True
        for fund in all_fund:
            yahoo = session().query(YahooTickerValue).filter(YahooTickerValue.ticker == '^BVSP').filter(
                YahooTickerValue.period == 'daily').filter(YahooTickerValue.time == fund.ref_date).one_or_none()

            if not yahoo or fund.ref_date.date().weekday():
                continue
            if first:
                first_fund = fund.quote_price
                first_bvsp = yahoo.close
                first = False
            graph['labels'].append(fund.ref_date.strftime('%m-%y') if fund.ref_date.day <= 8 else '')
            graph['series'][0].append(f'{100 * ((fund.quote_price / first_fund) - 1):.2f}')
            graph['series'][1].append(f'{100 * ((yahoo.close / first_bvsp) - 1):.2f}')

        today = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
        last_friday = (today.date()
                       - datetime.timedelta(days=today.weekday())
                       + datetime.timedelta(days=4, weeks=-1))
        last_month = today.replace(day=1)

        fund = session().query(DailyFund).order_by(DailyFund.ref_date.desc()).all()
        last_week_fund = session().query(DailyFund).filter(DailyFund.ref_date <= last_friday).order_by(
            DailyFund.ref_date.desc()).first()
        last_month_fund = session().query(DailyFund).filter(DailyFund.ref_date < last_month).order_by(
            DailyFund.ref_date.desc()).first()

        quote_holder = session().query(QuoteHolderMovements).all()
        qh_dict = {}
        final_bova, ref_date = session().query(YahooTickerValue.close, YahooTickerValue.time).filter(
            YahooTickerValue.ticker == '^BVSP').filter(
            YahooTickerValue.period == 'daily').order_by(YahooTickerValue.time.desc()).first()
        # final_bova = yahoo.close
        # ref_date = yahoo.time
        for qh in quote_holder:
            try:
                yahoo = session().query(YahooTickerValue).filter(YahooTickerValue.ticker == '^BVSP').filter(
                    YahooTickerValue.period == 'daily').filter(YahooTickerValue.time == qh.time).one()
                if not qh.name in qh_dict.keys():
                    qh_dict[qh.name] = {'bova': 0, 'sum': 0}
                qh_dict[qh.name]['bova'] = qh_dict[qh.name]['bova'] + qh.value * final_bova / yahoo.close
                qh_dict[qh.name]['sum'] = qh_dict[qh.name]['sum'] + qh.value
            except:
                print(qh.time)
        daily_qh = session().query(DailyQuoteHolder).filter(DailyQuoteHolder.ref_date == ref_date).order_by(
            DailyQuoteHolder.pl.desc()).all()
        quote_holder = {
            'header': ['Name', 'Quote Amount', 'Value', 'Return', 'Ibovespa'],
            'data': [],
        }
        for dqh in daily_qh:
            quote_holder['data'].append([dqh.name, f'{dqh.amount:.2f}', brl_format(dqh.pl),
                                         percentage_format(100 * (dqh.pl / qh_dict[dqh.name]['sum'] - 1)),
                                         percentage_format(100 * (qh_dict[dqh.name]['bova'] / qh_dict[dqh.name]['sum'] - 1))])

        table = {
            'patrimonial_equity': brl_format(fund[0].pl),
            'ref_date': fund[0].ref_date.strftime('%Y-%m-%d'),
            'cash': brl_format(fund[0].cash),
            'quote_amount': f'{fund[0].amount:.2f}',
            'quote_price': brl_format(fund[0].quote_price),
            'return': {
                'daily': [percentage_format(fund[0].pl / fund[1].pl), fund[1].ref_date.strftime('%Y-%m-%d')],
                'weekly': [percentage_format(fund[0].pl / last_week_fund.pl),
                           last_week_fund.ref_date.strftime('%Y-%m-%d')],
                'monthly': [percentage_format(fund[0].pl / last_month_fund.pl),
                            last_month_fund.ref_date.strftime('%Y-%m-%d')],
            },
            'graph': graph,
            'legend': {
                'names': ['Fund', 'Ibovespa'],
                'types': ['info', 'danger']
            },
            'quote_holder': quote_holder
        }
        return table


import re

str_pat = re.compile(r'\"(.*)\"')
text1 = 'Computer says "no."'
print(str_pat.findall(text1))

text2 = 'Computer says "no." Phone says "yes."'
print(str_pat.findall(text2))

#not greedy mode, add ? in the end
str_pat = re.compile(r'\"(.*?)\"')
print(str_pat.findall(text2))

comment = re.compile(r'/\*(.*?)\*/')
text1 = '/* this is a comment */'
text2 = '''/* this is a
multiline comment */
'''
print(comment.findall(text1))
print(comment.findall(text2))

comment = re.compile(r'/\*((?:.|\n)*?)\*/')
print(comment.findall(text2))

comment = re.compile(r'/\*(.*?)\*/', re.DOTALL)
print(comment.findall(text2))


from packet import Packet

class OtherhitPacket(Packet):

    def __init__(self, time=None, bulletId=None, objectId=None, targetId=None):
        self.time = time
        self.bulletId = bulletId
        self.objectId = objectId
        self.targetId = targetId

    def writeToOutput(self, stream):
        stream.writeInt(self.time)
        stream.writeByte(self.bulletId)
        stream.writeInt(self.objectId)
        stream.writeInt(self.targetId)


"""
Component dynamics storage.

@author: Gautham Ganapathy
@organization: LEMS (http://neuroml.org/lems/, https://github.com/organizations/LEMS)
@contact: gautham@lisphacker.org
"""

from lems.base.base import LEMSBase
from lems.base.errors import ModelError,ParseError
from lems.parser.expr import ExprParser

from lems.base.util import merge_dict

class StateVariable(LEMSBase):
    """
    Stores the definition of a state variable.
    """

    def __init__(self, name, exposure, dimension):
        """
        Constructor.

        @param name: Name (internal) of the state variable.
        @type name: string

        @param exposure: Name (external) of the state variable.
        @type exposure: string

        @param dimension: Dimension of the state variable.
        @type dimension: string
        """

        self.name = name
        """ Internal name of the state variable. This is the name used to
        refer to this variable inside the <Dynamics> element.
        @type: string """

        self.exposure = exposure
        """ Exposure name of the state variable. This is the name used to
        refer to this variable from other objects.
        @type: string """

        self.dimension = dimension
        """ Dimension of this state variable.
        @type: string """

class TimeDerivative(LEMSBase):
    """
    Stores the time derivative expression for a given state variable.
    """

    def __init__(self, variable, value):
        """
        Constructor.

        @param variable: Name of the state variable
        @type variable: string

        @param value: Time derivative expression of the given state variable.
        @type value: string
        """

        self.variable = variable
        """ State variable whose time derivative is stored in this object.
        @type: string """

        self.value = value
        """ Time derivative expression for the state variable.
        @type: string """

        try:
            self.expression_tree = ExprParser(value).parse()
            """ Parse tree for the time derivative expression.
            @type: lems.parser.expr.ExprNode """
        except:
            raise ParseError("Parse error when parsing value expression "
                             "'{0}' for derived variable {1}".format(\
                                 self.value,
                                 self.variable))

class DerivedVariable(LEMSBase):
    """
    Stores the definition of a derived variable.
    """

    def __init__(self, name, exposure, dimension, value, select, reduce):
        """
        Constructor.

        @param name: Name (internal) of the derived variable.
        @type name: string

        @param exposure: Name (external) of the derived variable.
        @type exposure: string

        @param dimension: Dimension of the derived variable.
        @type dimension: string

        @param value: Value expression for the derived variable.
        @type value: string

        @param select: Target component selection for reduction operations.
        @type select: string

        @param reduce: Reduce operation.
        @type reduce: string
        """

        self.name = name
        """ Internal name of the derived variable. This is the name used to
        refer to this variable inside the <Dynamics> element.
        @type: string """

        self.exposure = exposure
        """ Exposure name of the derived variable. This is the name used to
        refer to this variable from other objects.
        @type: string """

        self.dimension = dimension
        """ Dimension of this derived variable.
        @type: string """

        self.value = value
        """ Expression used for computing the value of the derived variable.
        @type: string """

        self.select = select
        """ Selected target object for the reduce operation.
        @type: string """

        self.reduce = reduce
        """ Reduce operation to be applied over the selected target.
        @type: string """

        if value != None:
            try:
                self.expression_tree = ExprParser(value).parse()
                """ Parse tree for the time derivative expression.
                @type: lems.parser.expr.ExprNode """
            except:
                raise ParseError("Parse error when parsing value expression "
                                 "'{0}' for derived variable {1}".format(\
                                     self.value,
                                     self.name))
        else:
            self.expression_tree = None

class EventHandler(LEMSBase):
    """
    Base class for event an handler.
    """

    ON_START = 1
    ON_ENTRY = 2
    ON_EVENT = 3
    ON_CONDITION = 4

    def __init__(self, type):
        """
        Constructor.

        @param type: Type of event.
        @type type: enum(EventHandler.ONSTART, EventHandler.ON_ENTRY,
        EventHandler.ON_EVENT and EventHandler.ON_CONDITION)
        """

        self.type = type
        """ Type of event.
        @type: enum(EventHandler.ONSTART, EventHandler.ON_ENTRY,
        EventHandler.ON_EVENT and EventHandler.ON_CONDITION) """

        self.actions = []
        "List of actions to be performed on the occurence of the event."

    def add_action(self, action):
        """
        Adds an action to the list of actions.

        @param action: Action to be performed.
        @type action: lems.model.dynamics.Action
        """

        self.actions += [action]

    def check_for_event(self):
        """
        Check for the event. If this function returns true, the corresponding
        event actions will be executed.

        @return: Check if the event has occurred.
        @rtype: Boolean

        @note: This function must be overridden. Maybe when building the
        simulator?
        """

        return False

class OnStart(EventHandler):
    """
    Stores the parameters of an <OnStart> statement.
    """

    def __init__(self):
        """
        Constructor.
        """

        EventHandler.__init__(self, EventHandler.ON_START)

    def __str__(self):
        """ Generates a string representation of this condition."""

        return 'OnStart'

class OnEntry(EventHandler):
    """
    Stores the parameters of an <OnEntry> statement.
    """

    def __init__(self):
        """
        Constructor.
        """

        EventHandler.__init__(self, EventHandler.ON_ENTRY)

    def __str__(self):
        """ Generates a string representation of this condition."""

        return 'OnEntry'

class OnEvent(EventHandler):
    """
    Stores the parameters of an <OnEvent> statement.
    """

    def __init__(self, port):
        """
        Constructor.

        @param port: The name of the event port to listen on.
        @type port: string
        """

        EventHandler.__init__(self, EventHandler.ON_EVENT)

        self.port = port
        """ The name of the event port to listen on.
        @type: string """

    def __str__(self):
        """ Generates a string representation of this condition."""

        return 'OnEvent: ' + self.port

class OnCondition(EventHandler):
    """
    Event handler for a condition check.
    """

    def __init__(self, test):
        """
        Constructor.

        @param test: Test expression.
        @type test: string
        """

        EventHandler.__init__(self, EventHandler.ON_CONDITION)

        self.test = test
        """ Test expression.
        @type: string """

        self.expression_tree = ExprParser(test).parse()
        """ Parse tree for the test expression.
        @type: lems.parser.expr.ExprNode """

    def __str__(self):
        """ Generates a string representation of this condition."""

        return 'OnCondition: ' + self.test + ' | ' +\
               str(self.expression_tree)

class Action(LEMSBase):
    """
    Base class for an event action.
    """

    STATE_ASSIGNMENT = 1
    EVENT_OUT = 2
    TRANSITION = 3

    def __init__(self, type):
        """
        Constructor.

        @param type: Type of action.
        @type type: enum(Action.STATEASSIGNMENT, Action.EVENT_OUT)
        """

        self.type = type
        """ Type of action.
        @type: enum(Action.STATEASSIGNMENT, Action.EVENT_OUT) """

class StateAssignment(Action):
    """
    Stores a state assignment expression.
    """

    def __init__(self, variable, value):
        """
        Constructor.

        @param variable: Name of the state variable
        @type variable: string

        @param value: Assignment expression of the given state variable.
        @type value: string
        """

        Action.__init__(self, Action.STATE_ASSIGNMENT)

        self.variable = variable
        """ State variable whose assignment expression is stored in this
        object.
        @type: string """

        self.value = value
        """ Assignment expression for the state variable.
        @type: string """

        self.expression_tree = ExprParser(value).parse()
        """ Parse tree for the assignment expression.
        @type: lems.parser.expr.ExprNode """

    def __str__(self):
        """ Generates a string representation of this state assigment """

        return self.variable + ' <- ' + self.value + ' | ' + \
               str(self.expression_tree)

class EventOut(Action):
    """
    Stores an event out operation.
    """

    def __init__(self, port):
        """
        Constructor.

        @param port: Name of a port
        @type port: string
        """

        Action.__init__(self, Action.EVENT_OUT)

        self.port = port
        """ Name of the port to which the event needs to be sent.
        @type: string """

    def __str__(self):
        """ Generates a string representation of this state assigment """

        return 'Event -> ' + self.port

class Transition(Action):
    """
    Stores an regime transition operation.
    """

    def __init__(self, regime):
        """
        Constructor.

        @param regime: Name of a dynamics regime
        @type regime: string
        """

        Action.__init__(self, Action.TRANSITION)

        self.regime = regime
        """ Name of the dynamics regime to switch to.
        @type: string """

    def __str__(self):
        """ Generates a string representation of this state assigment """

        return 'Regime -> ' + self.regime

class KineticScheme(LEMSBase):
    """
    Stores a kinetic scheme specification.
    """

    def __init__(self, name, nodes, state_variable,
                 edges, edge_source, edge_target,
                 forward_rate, reverse_rate):
        """
        Constructor.

        See instance variable documentation for info on parameters.
        """

        self.name = name
        """ Name of the kinetic scheme.
        @type: string """

        self.nodes = nodes
        """ Name of the children collection specifying the nodes
        for the kinetic scheme.
        @type: string """

        self.state_variable = state_variable
        """ Name of the state variable in the KS node specifying
        the value of the scheme.
        @type: string """

        self.edges = edges
        """ Name of the children collection specifying the edges
        for the kinetic scheme.
        @type: string """

        self.edge_source = edge_source
        """ Name of the link in a KS edge pointing to the source
        node for the edge.
        @type: string """

        self.edge_target = edge_target
        """ Name of the link in a KS edge pointing to the target
        node for the edge.
        @type: string """

        self.forward_rate = forward_rate
        """ Name of the state variable in a KS edge specifying
        forward rate for the edge.
        @type: string """

        self.reverse_rate = reverse_rate
        """ Name of the state variable in a KS edge specifying
        reverse rate for the edge.
        @type: string """

class Regime(LEMSBase):
    """
    Store a dynamics regime for a component type.
    """

    def __init__(self, name, initial = False):
        """
        Constructor.

        @param name: Name of the dynamics regime.
        @type name: string

        @param initial: Is this the initial regime? Default: False
        @type initial: Boolean
        """

        self.name = name
        """ Name of this ehavior regime.
        @type: string """

        self.initial = initial
        """ Is this an initial regime?
        @type: Boolean """

        self.state_variables = {}
        """ Dictionary of state variables defined in this dynamics regime.
        @type: dict(string -> lems.model.dynamics.StateVariable) """

        self.time_derivatives = {}
        """ Dictionary of time derivatives defined in this dynamics regime.
        @type: dict(string -> lems.model.dynamics.TimeDerivative) """

        self.derived_variables = {}
        """ Dictionary of derived variables defined in this dynamics regime.
        @type: dict(string -> lems.model.dynamics.DerivedVariable) """

        self.event_handlers = []
        """ List of event handlers defined in this dynamics regime.
        @type: list(EventHandler) """

        self.kinetic_schemes = {}
        """ Dictionary of kinetic schemes defined in this dynamics regime.
        @type: dict(string -> lems.model.dynamics.KineticScheme) """

    def add_state_variable(self, name, exposure, dimension):
        """
        Adds a state variable to the dynamics current object.

        @param name: Name of the state variable.
        @type name: string

        @param exposure: Exposed name of the state variable.
        @type exposure: string

        @param dimension: Dimension ofthe state variable.
        @type dimension: string

        @raise ModelError: Raised when the state variable is already
        defined in this dynamics regime.
        """

        if name in self.state_variables:
            raise ModelError('Duplicate state variable ' + name)

        self.state_variables[name] = StateVariable(name, exposure, dimension)

    def add_time_derivative(self, variable, value):
        """
        Adds a state variable to the dynamics current object.

        @param variable: Name of the state variable whose time derivative
        is being specified.
        @type variable: string

        @param value: Time derivative expression.
        @type value: string

        @raise ModelError: Raised when the time derivative for this state
        variable is already defined in this dynamics regime.
        """

        if variable in self.time_derivatives:
            raise ModelError('Duplicate time derivative for ' + variable)

        self.time_derivatives[variable] = TimeDerivative(variable, value)

    def add_derived_variable(self, name, exposure, dimension,
                             value, select, reduce):
        """
        Adds a derived variable to the dynamics current object.

        @param name: Name of the derived variable.
        @type name: string

        @param exposure: Exposed name of the derived variable.
        @type exposure: string

        @param dimension: Dimension ofthe derived variable.
        @type dimension: string

        @param value: Value expression for the derived variable.
        @type value: string

        @param select: Target component selection for reduction operations.
        @type select: string

        @param reduce: Reduce operation.
        @type reduce: string

        @raise ModelError: Raised when the derived variable is already
        defined in this dynamics regime.
        """

        if name in self.derived_variables:
            raise ModelError("Duplicate derived variable '{0}'".format(name))

        if value == None and select == None and reduce == None:
            raise ModelError("Derived variable '{0}' must specify either a "
                             "value expression or a reduce "
                             "operation".format(name))

        if value != None and (select != None or reduce != None):
            raise ModelError("Derived variable '{0}' cannot specify both "
                             "value expressions or select/reduce "
                             "operations".format(name))

        if select == None and reduce != None:
            raise ModelError("Reduce target not specified for derived "
                             "variable '{0}'".format(name))

        self.derived_variables[name] = DerivedVariable(name, exposure,
                                                       dimension, value,
                                                       select, reduce)

    def add_event_handler(self, event_handler):
        """
        Adds a state variable to the dynamics current object.

        @param event_handler: Event handler object.
        @type event_handler: lems.model.dynamics.EventHandler
        """

        self.event_handlers += [event_handler]

    def add_kinetic_scheme(self, name, nodes, state_variable,
                           edges, edge_source, edge_target,
                           forward_rate, reverse_rate):
        """
        Constructor.

        See KineticScheme documentation for info on parameters.

        @raise ModelError: Raised if a kinetic scheme with the same
        name already exists in this behavior regime.
        """

        if name in self.kinetic_schemes:
            raise ModelError('Duplicate kinetic scheme ' + name)

        self.kinetic_schemes[name] = KineticScheme(name, nodes, state_variable,
                                                   edges, edge_source, edge_target,
                                                   forward_rate, reverse_rate)

    def merge(self, regime):
        """
        Merge another regime into this one.

        @param regime: Regime to be merged in.
        @type regime: lems.model.dynamics.Regime
        """

        merge_dict(self.state_variables, regime)
        merge_dict(self.time_derivatives, regime.time_derivatives)
        merge_dict(self.derived_variables, regime.derived_variables)

        self.event_handlers += regime.event_handlers

        merge_dict(self.kinetic_schemes, regime.kinetic_schemes)

class Dynamics(LEMSBase):
    """
    Stores the dynamic dynamics for a component type.
    """

    def __init__(self, name):
        """
        Constructor.
        """

        self.name = name
        """ Name of this dynamics profile.
        @type: string """

        self.default_regime = Regime('')
        """ Default dynamics regime for this dynamics profile. This regime
        is used to store dynamics object not defined within a named regime.
        @type: lems.model.dynamics.Regime """

        self.current_regime = None
        """ Currently active dynamics regime for this dynamics profile.
        @type: lems.model.dynamics.Regime """

        self.regimes = {}
        """ Dictionary of regimes in this dynamics profile.
        @type: dict(string -> lems.model.dynamics.Regime) """

    def add_regime(self, name, initial = False):
        """
        Adds a dynamics regime to the list of regimes in this dynamics
        profile.

        @param name: Name of the dynamics regime.
        @type name: string

        @param initial: Is this the initial regime? Default: False
        @type initial: Boolean
        """

        if name in self.regimes:
            raise ModelError('Duplicate regime ' + name)

        if initial:
            for rn in self.regimes:
                if self.regimes[rn].initial:
                    raise('Cannot define two initial regimes in the same' +
                          ' dynamics profile')

        regime = Regime(name, initial)
        if initial:
            self.current_regime = regime

        self.regimes[name] = regime

    def merge(self, dynamics):
        """
        Merge another dynamics profile into this one.

        @param dynamics: Dynamics profile to be merged in.
        @type dynamics: lems.model.dynamics.Dynamics
        """

        self.default_regime.merge(dynamics.default_regime)

        if not self.current_regime:
            self.current_regime = dynamics.current_regime

        for rn in dynamics.regimes:
            if rn in self.regimes:
                self.regimes[rn].merge(dynamics.regimes[rn])
            else:
                self.regimes[rn] = dynamics.regimes[rn]


from struct import pack
import numpy

# Start of MPL registers
MPL115A2_ADDRESS = b'\x60'
MPL115A2_REGISTER_PRESSURE_MSB = b'\x00'
MPL115A2_REGISTER_PRESSURE_LSB = b'\x01'
MPL115A2_REGISTER_TEMP_MSB = b'\x02'
MPL115A2_REGISTER_TEMP_LSB = b'\x03'
MPL115A2_REGISTER_A0_COEFF_MSB = b'\x04'
MPL115A2_REGISTER_A0_COEFF_LSB = b'\x05'
MPL115A2_REGISTER_B1_COEFF_MSB = b'\x06'
MPL115A2_REGISTER_B1_COEFF_LSB = b'\x07'
MPL115A2_REGISTER_B2_COEFF_MSB = b'\x08'
MPL115A2_REGISTER_B2_COEFF_LSB = b'\x09'
MPL115A2_REGISTER_C12_COEFF_MSB = b'\x0A'
MPL115A2_REGISTER_C12_COEFF_LSB = b'\x0B'
MPL115A2_REGISTER_STARTCONVERSION = b'\x12'

class MPL:
   def __init__(self, sim=None):
      self.sim = sim
      self.pressure = 0.0
      self.temperature = 0.0
   # end def

   def update_values(self, sim):
      self.pressure = sim.pressure
      self.temperature = sim.temperature
   # end def

   def encode_temp(self):
      return round(self.temperature * 100)
   # end def

   def encode_pres(self):
      return round(self.pressure / 5)
   # end def

   # sigma = 0.013
   def addNoiseTemp(self, value, dev):
      #print( "Value: ", value, end="")
      valueWithNoise = numpy.random.normal(value, dev)
      #print (", Value With Noise: ", valueWithNoise)
      valueWithNoise = round(valueWithNoise * 100)
      return valueWithNoise
   # end def

   # sigma = 0.013
   def addNoisePress(self, value, dev):
      valueWithNoise = numpy.random.normal(value, dev)
      #print (value, ",", valueWithNoise)
      valueWithNoise = round(valueWithNoise / 5)

      return valueWithNoise
   # end def

   def receive(self, con):
      data = con.receive(1)
      if self.sim is not None:
         self.update_values(self.sim)
      # end if
      if data == MPL115A2_REGISTER_PRESSURE_MSB:
         # print("MPL: Sending P=",self.pressure,", T=",self.temperature, end = ", ")
         packet = bytearray(
             pack(">h", self.addNoisePress(self.pressure, 33.33)))
         packet.extend(
             bytearray(pack(">h", self.addNoiseTemp(self.temperature, 0.33))))
         con.send(packet)
      else:
         print("MPL: Unknown command received: ", data)
   # end def
# end class


import datetime
from collections import Counter

import pandas as pd
import weka
import weka.core.converters as converters
import weka.core.jvm as jvm
from numpy import load
from weka.classifiers import Classifier, PredictionOutput, Evaluation
from weka.core.classes import Random

from utils import *

def java_start(path_packages):
    jvm.start(packages=path_packages)

def java_stop():
    jvm.stop()

def create_prediction(col_label, col_prediction, col_different, indicator, images, name, path):
    check_folder_or_create(path)
    df = pd.DataFrame()
    df['indicator'] = indicator
    df['image'] = images
    df['label'] = col_label
    df['prediction'] = col_prediction
    df['different'] = col_different
    df['prediction'] = list(map(lambda x: (x[2:]), df['prediction']))
    df['label'] = list(map(lambda x: (x[2:]), df['label']))
    df.to_csv(path + name + 'pred_data.csv', index=False)

def experiment_sequential_file(path_indices, path_features, path_folder_save_results, options, classifier, name,
                               indicator_col, images):
    ind_f = load(path_indices)
    lst = ind_f.files

    for item in lst:
        ind = ind_f[item] + 1

    cls = Classifier(classname=classifier, options=weka.core.classes.split_options(options))

    data = converters.load_any_file(path_features)

    ind = np.append(ind, len(data))

    data.class_is_last()

    pout = PredictionOutput(classname="weka.classifiers.evaluation.output.prediction.CSV")

    d_results = {'index': [], 'percent_correct': [], 'percent_incorrect': [], 'precision': [], 'recall': [], 'f-score': [], 'confusion_matrix': []}

    for j in range(len(ind) - 1):
        first = ind[j]

        if j == len(ind) - 2:
            last = ind[j + 1]
        else:
            last = ind[j + 1] - 1

        d_test = data.subset(row_range=str(first) + '-' + str(last))

        if j == 0:  # first
            d_train = data.subset(row_range=str(last + 1) + '-' + str(ind[-1]))  # last element
            print(str(last + 1) + '-' + str(ind[-1]))
        elif j == len(ind) - 2:  # last
            d_train = data.subset(row_range='1-' + str(first - 1))  # last element
            print('1-' + str(first - 1))
        else:  # central
            s = '1-' + str(first - 1) + ',' + str(last + 1) + '-' + str(ind[-1])
            print(s)
            d_train = data.subset(row_range=s)

        cls.build_classifier(d_train)

        evl = Evaluation(data)
        evl.test_model(cls, d_test, pout)

        # print(type(d_train))
        # print(type(d_test))

        d_results['index'].append(str(ind[j]))
        d_results['percent_correct'].append(evl.percent_correct)
        d_results['percent_incorrect'].append(evl.percent_incorrect)
        d_results['precision'].append(evl.precision(1))
        d_results['recall'].append(evl.recall(1))
        d_results['f-score'].append(evl.f_measure(1))
        d_results['confusion_matrix'].append(evl.matrix())  # Generates the confusion matrix.

    save = pout.buffer_content()

    check_folder_or_create(path_folder_save_results + '/' + 'prediction')

    with open(path_folder_save_results + '/' + 'prediction/' + name + 'pred_data.csv', 'w') as f:
        f.write(save)

    buffer_save = pd.read_csv(path_folder_save_results + '/' + 'prediction/' + name + 'pred_data.csv', index_col=False, header=None)

    col_label = buffer_save[1]
    col_prediction = buffer_save[2]
    col_different = buffer_save[3]

    create_prediction(col_label, col_prediction, col_different, indicator_col, images, name, path_folder_save_results + '/prediction/')

    d_results = pd.DataFrame(data=d_results)

    d_results.to_csv(path_folder_save_results + '/' + name + 'results.csv', index=False)

def experiment_file_random(path_features, path_folder_save_results, options, classifier, fold, random, name):
    print(name + "  Start: " + str(datetime.datetime.now()))
    time = datetime.datetime.now()
    cls = Classifier(classname=classifier, options=weka.core.classes.split_options(options))
    d_results = {'percent_correct': [], 'percent_incorrect': [], 'precision': [], 'recall': [], 'f-score': [], 'confusion_matrix': []}
    data = converters.load_any_file(path_features)
    data.class_is_last()
    pout = PredictionOutput(classname="weka.classifiers.evaluation.output.prediction.CSV")
    evl = Evaluation(data)
    evl.crossvalidate_model(cls, data, fold, Random(random), pout)
    d_results['percent_correct'].append(evl.percent_correct)
    d_results['percent_incorrect'].append(evl.percent_incorrect)
    d_results['precision'].append(evl.precision(1))
    d_results['recall'].append(evl.recall(1))
    d_results['f-score'].append(evl.f_measure(1))
    d_results['confusion_matrix'].append(evl.matrix())  # Generates the confusion matrix.

    d_results = pd.DataFrame(data=d_results)

    d_results.to_csv(path_folder_save_results + '/' + str(name) + '.csv', index=False)

    save = pout.buffer_content()

    check_folder_or_create(path_folder_save_results + '/' + 'prediction')

    with open(path_folder_save_results + '/' + 'prediction/' + str(name) + '.csv', 'w') as f:
        f.write(save)
    print(name + "  End: " + str(datetime.datetime.now() - time))

def experiment_more_file(path_files, path_folder_save_results, fold, options, classifier, random, name, voting=False):
    cls = Classifier(classname=classifier, options=weka.core.classes.split_options(options))

    file_list = os.listdir(path_files)

    for file in file_list:
        if ".csv" not in file:
            file_list.remove(file)

    d_results = {'name_file': [], 'percent_correct': [], 'percent_incorrect': [], 'precision': [], 'recall': [], 'f-score': [], 'confusion_matrix': []}

    for file in file_list:
        indicator_table = pd.read_csv(path_files + '/indicator/' + file[0] + '_indicator.csv')
        indicator = list(indicator_table['indicator'])
        images = list(indicator_table['image'])

        data = converters.load_any_file(path_files + "/" + file)

        data.class_is_last()

        pout = PredictionOutput(classname="weka.classifiers.evaluation.output.prediction.CSV")

        evl = Evaluation(data)

        evl.crossvalidate_model(cls, data, fold, Random(random), pout)

        d_results['name_file'].append(str(file))
        d_results['percent_correct'].append(evl.percent_correct)
        d_results['percent_incorrect'].append(evl.percent_incorrect)
        d_results['precision'].append(evl.precision(1))
        d_results['recall'].append(evl.recall(1))
        d_results['f-score'].append(evl.f_measure(1))
        d_results['confusion_matrix'].append(evl.matrix())  # Generates the confusion matrix.

        save = pout.buffer_content()

        check_folder_or_create(path_folder_save_results + '/' + name + '/' + 'prediction')

        with open(path_folder_save_results + '/' + name + '/' + 'prediction/pred_data.csv',
                  'w') as f:
            f.write(save)

        buffer_save = pd.read_csv(path_folder_save_results + '/' + name + '/' + 'prediction/pred_data.csv',
                                  index_col=False)

        col_label = buffer_save['actual']
        col_prediction = buffer_save['predicted']
        col_different = buffer_save['error']

        create_prediction(col_label, col_prediction, col_different, indicator, images, file[:-4],
                          path_folder_save_results + '/' + name + '/prediction/')

    d_results = pd.DataFrame(data=d_results)

    d_results.to_csv(path_folder_save_results + '/' + str(name) + ".csv")

def check(indicator, image_labels, details_indicator):
    flag = False
    if len(image_labels) % 2 == 0:
        most_c = Counter(image_labels).most_common()
        if len(most_c) == 2:
            a = Counter(image_labels).most_common()[0]
            b = Counter(image_labels).most_common()[1]
            if a[1] == b[1]:
                flag = True
                details_indicator[indicator]['tot'] = details_indicator[indicator]['tot'] + 1
                if a[0] == 'attentive':
                    details_indicator[indicator]['attentive first'] = details_indicator[indicator][
                                                                          'attentive first'] + 1
                else:
                    details_indicator[indicator]['distracted first'] = details_indicator[indicator][
                                                                           'distracted first'] + 1
    return details_indicator, flag

def voting_version_check_len(path_file_prediction, folder_to_save_results):
    predictions = [pd.read_csv(path_file_prediction + "/" + str(el), index_col=False) for el in
                   sorted(os.listdir(path_file_prediction))]
    name_files = sorted(os.listdir(path_file_prediction))

    for i in range(len(predictions)):
        image_labels = list()
        prediction = list()

        details_indicator = {'over time':
                                 {"tot": 0, 'attentive first': 0, 'distracted first': 0, 'label assigned attentive': 0,
                                  'label assigned distracted': 0},
                             'attentive':
                                 {"tot": 0, 'attentive first': 0, 'distracted first': 0, 'label assigned attentive': 0,
                                  'label assigned distracted': 0},
                             'error-no over time':
                                 {"tot": 0, 'attentive first': 0, 'distracted first': 0, 'label assigned attentive': 0,
                                  'label assigned distracted': 0},
                             'error-over time':
                                 {"tot": 0, 'attentive first': 0, 'distracted first': 0, 'label assigned attentive': 0,
                                  'label assigned distracted': 0},
                             }

        p = predictions[i]
        #print(p.columns)

        if list(p.columns) == ['indicator', 'image', 'label', 'prediction', 'different']:

            for index in range(p.shape[0]):
                if len(image_labels) > 0:
                    if p['image'][index] != p['image'][index - 1]:

                        details_indicator, flag = check(p['indicator'][index - 1], image_labels, details_indicator)

                        if flag:
                            if len(image_labels) > 4:
                                vote = 'distracted'
                                details_indicator[p['indicator'][index - 1]]['label assigned distracted'] = \
                                    details_indicator[p['indicator'][index - 1]]['label assigned distracted'] + 1
                            else:
                                vote = 'attentive'
                                details_indicator[p['indicator'][index - 1]]['label assigned attentive'] = \
                                    details_indicator[p['indicator'][index - 1]]['label assigned attentive'] + 1
                        else:
                            vote = Counter(image_labels).most_common()[0][0]

                        if vote != p['label'][index - 1]:
                            sign = 'incorrect'
                        else:
                            sign = 'correct'

                        prediction.append(
                            (p['image'][index - 1], p['indicator'][index - 1], p['label'][index - 1], vote, sign))
                        image_labels = list()

                image_labels.append(p['prediction'][index])

            create_results_voting(prediction, folder_to_save_results, name_files[i][:-4], i, details_indicator)

def voting(path_file_prediction, folder_to_save_results):
    predictions = [pd.read_csv(path_file_prediction + "/" + str(el), index_col=False) for el in
                   sorted(os.listdir(path_file_prediction))]
    name_files = sorted(os.listdir(path_file_prediction))

    for i in range(len(predictions)):
        image_labels = list()
        prediction = list()

        details_indicator = {'over time':
                                 {"tot": 0, 'attentive first': 0, 'distracted first': 0},
                             'attentive':
                                 {"tot": 0, 'attentive first': 0, 'distracted first': 0},
                             'error-no over time':
                                 {"tot": 0, 'attentive first': 0, 'distracted first': 0},
                             'error-over time':
                                 {"tot": 0, 'attentive first': 0, 'distracted first': 0},
                             }

        p = predictions[i]

        if list(p.columns) == ['indicator', 'image', 'label', 'prediction', 'different'] or list(p.columns) == ['instance','label','prediction','different','perc_error','indicator','image']:

            for index in range(p.shape[0]):
                if len(image_labels) > 0:
                    if p['image'][index] != p['image'][index - 1]:
                        vote = Counter(image_labels).most_common()[0][0]

                        details_indicator, flag = check(p['indicator'][index - 1], image_labels, details_indicator)

                        if vote != p['label'][index - 1]:
                            sign = 'incorrect'
                        else:
                            sign = 'correct'

                        prediction.append(
                            (p['image'][index - 1], p['indicator'][index - 1], p['label'][index - 1], vote, sign))
                        image_labels = list()

                image_labels.append(p['prediction'][index])

            create_results_voting(prediction, folder_to_save_results, name_files[i][:-4], i, details_indicator)

def create_results_voting(prediction, folder_to_save_results, name_file, i, details_indicator):
    df = pd.DataFrame(prediction, columns=['image', 'indicator', 'original label', 'prediction', 'status'])
    check_folder_or_create(folder_to_save_results + '/details')

    sys.stdout = open(folder_to_save_results + '/details/' + name_file + '_' + ".csv", "w")
    print(name_file)
    print('\n')
    print('perc incorrect: ' + str((list(df['status']).count('incorrect') * 100) / df.shape[0]))
    print('perc correct: ' + str((list(df['status']).count('correct') * 100) / df.shape[0]))
    print('\n')
    df.to_csv(folder_to_save_results + '/' + str(i) + 'prediction_voting.csv')
    c = [x for _, x in df.groupby(['status'])]
    print("Numero totale di immagini divise per indicatore:\n" + str(
        (df[['indicator', 'image']].groupby(['indicator']).count())))
    print('\n\n')
    print("Numero di immagini classificate scorrettamente con indicatore:\n" + str(
        (c[1][['indicator', 'status']].groupby(['indicator']).count())))
    print('\n')
    print("Numero di immagini classificate scorrettamente con label:\n" + str(
        (c[1][['original label', 'status']].groupby(['original label']).count())))
    print('\n\n')
    print("Caso feature pari e nessuna classe in numero maggiore: \n")
    print('attentive')
    print(details_indicator['attentive'])
    print("over time")
    print(details_indicator['over time'])
    print("error-no over time")
    print(details_indicator['error-no over time'])
    print("error-over time")
    print(details_indicator['error-over time'])
    sys.stdout.close()


# -*- encode: utf-8 -*-
from copy import copy
from functools import partial, wraps
from typing import Hashable, Callable

class Pipe:
	def __init__(self, func=None, *args, **kwargs):
		# initialization args
		self.func = func
		self.args = args
		self.kwargs = kwargs
		# attributions
		self.cache = kwargs.get('cache', False)
		self.unpack = kwargs.get('unpack', False)
		self.append = kwargs.get('append', False)
		self.done = False
		# cached result
		self.result = {None:None}

	def __repr__(self):
		cached = '(cached)' if self.cache else ''
		unpacked = '(unpacked)' if self.unpack else ''
		appended = '(appended)' if self.append else ''
		hash_ = hash(self)
		return f'<Pipe{cached}{unpacked}{appended} @ {hash_:#x}>'

	def __or__(self, value):
		assert isinstance(value, (Pipe, Callable)), 'Pipe or Callable required.'
		if isinstance(value, Pipe) and self.func is None:
			return value(self())
		def couple(*args, **kwargs):
			return value(self(*args, **kwargs))
		return Pipe(couple)

	def __ror__(self, value):
		return self(value)

	def __getitem__(self, args):
		if isinstance(args, dict):
			args, kwargs = tuple(), args
		elif isinstance(args, tuple):
			args, kwargs = args, dict()
		elif len(args) == 0:
			args, kwargs = tuple(), dict()
		elif len(args) == 1:
			args, kwargs = (tuple(), args[0]) if isinstance(args[0], dict) else \
				(tuple(args[0]), dict())
		elif len(args) == 2:
			args, kwargs = args
		assert isinstance(args, tuple), 'Argument type error.'
		assert isinstance(kwargs, dict), 'Argument type error.'
		temp = self.copy()
		temp.args += args
		temp.kwargs.update(kwargs)
		return temp

	def __call__(self, arg=None, *args, **kwargs):
		if self.unpack:
			args = (args+arg) if self.append else (arg+args)
		else:
			assert args==(), 'One argument required if not unpacked.'
			assert kwargs=={}, 'One argument required if not unpacked.'
		if self.func is None:
			result = tuple(filter(bool, (arg, self.args, self.kwargs)))
			if not result:
				return None
			elif len(result) == 1:
				return result[0]
			return result
		elif isinstance(arg, Pipe):
			return self.func(*arg.args, **arg.kwargs)
		if arg is not None:
			if self.unpack:
				args = (self.args+args) if self.append else (args+self.args)
				kwargs.update(self.kwargs)
			if self.cache:
				if isinstance(arg, Hashable):
					if arg not in self.result:
						self.result[arg] = \
							self.func(*args, **kwargs) if self.unpack else \
							self.func(arg, *self.args, **self.kwargs)
					return self.result[arg]
			return self.func(*args, **kwargs) if self.unpack else \
				(self.func(*self.args, arg, **self.kwargs) if self.append else \
					self.func(arg, *self.args, **self.kwargs))
		else:
			if self.cache:
				if not self.done:
					self.result[None] = \
						self.func(*self.args, **self.kwargs)
					self.done = True
				return self.result[None]
			return self.func(*self.args, **self.kwargs)

	def copy(self):
		return copy(self)

	def enable_cache(self):
		self.cache = True
		return self

	def enable_unpack(self):
		self.unpack = True
		return self

	def enable_append(self):
		self.append = True
		return self

def piped(func=None, cache=False, unpack=False, append=False, *args, **kwargs):
	if func is None:
		return partial(piped, cache=cache, unpack=unpack, append=append)
	result = Pipe(func, *args, **kwargs)
	if cache:  result=result.enable_cache()
	if unpack: result=result.enable_unpack()
	if append: result=result.enable_append()
	return result

if __name__ == '__main__':
	# example 1
	from operator import neg
	from random import randint
	from shutil import get_terminal_size

	r = 3.1415927
	int = Pipe(int)
	neg = Pipe(neg).enable_cache()
	abs = Pipe(abs).enable_cache()
	rnd = Pipe(randint, r|int|neg, r|int|abs)
	add = Pipe(lambda x: x+(r|int|abs))
	echo = Pipe(print, end=', ')

	col, row = get_terminal_size()
	length = min(col, row) // 2
	for _ in range(length):
		for __ in range(length):
			(rnd | add)() | echo
		print()

	# example 2
	import matplotlib.pyplot as plt

	x = (1, 2, 3, 4, 5)
	y = (2, 4, 1, 3, 5)
	z = (4, 2, 5, 3, 1)
	plot = Pipe(plt.plot).enable_unpack()
	args = Pipe(None, x, y)
	args | plot
	(x, z) | plot

	plt.show()

	# example 3
	@piped(unpack=True)
	def echo_(*args):
		print(*args, sep=', ')
		print()
	(1, 2, 3) | echo_

	# example 4
	echo__ = Pipe(print, sep=',' ).enable_unpack()
	(1, 2, 3) | echo__[{'sep': ' - '}]

	# example 5
	where = Pipe(filter).enable_append()
	tuple_ = Pipe(tuple)
	print_ = piped(unpack=True)(print, sep=': ')
	(1, 2, 3, 4) | where[(lambda x: x%2==0, )] | tuple_ | print_


from django.shortcuts import render, redirect
from django.http import HttpResponse
from .forms import SearchForm
from  .controllers.Spotify import Spotify
from django.urls import reverse
from radio.models import Entity, EntityQueue, Song
from django.template.loader import render_to_string
from django.template import loader

import json
import requests
# Create your views here.
def index(request):
    if request.method == "POST":
        form = SearchForm(request.POST)
        if form.is_valid():
            search = form.save(commit=False)
            resultType = search.resultType
            query = search.query
            platform = search.platform
            spotify = Spotify(search)
            jsonFilePath = spotify.search(request)
            return redirect('./results/' + jsonFilePath)

    else:
        form = SearchForm()
        return render(request, 'search/searchForm.html', {'form': form})

def results(request, jsonFilePath):
    completePath = './search/results/' + jsonFilePath
    print(completePath)
    jsonData = open(completePath).read()
    searchData = json.loads(jsonData)
    songs = searchData['tracks']['items']

    searchResults = []

    for jsonSong in songs:
        song = Song()
        song.name = jsonSong['name']
        song.artist = jsonSong['artists'][0]['name']
        song.album = jsonSong['album']['name']
        song.release = jsonSong['album']['release_date']
        song.popularity = jsonSong['popularity']
        song.spotifyID = jsonSong['id']
        song.image_url = jsonSong['album']['images'][0]['url']
        searchResults.append(song)
        del song

    baseContext = {
        'search_results': searchResults,
    }

    return render(request, './song-small.html', baseContext)

def song(request):
    return render(request, './song-small.html')


import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from sklearn.externals import joblib

class MyGrid(Widget):
    title = ObjectProperty(None)
    author = ObjectProperty(None)
    isi = ObjectProperty(None)

    def btn(self):
        a = self.title.text
        b = self.author.text
        c = self.isi.text

        gabung = a+b+c
        filename = './pipeline.sav'
        loaded_model = joblib.load(filename)
        pred = loaded_model.predict([gabung])
        if (pred == [1]) :
           result = 'Real'
        elif (pred == [0]):
            result = 'Fake'
        else:
            result = 'Nothing'

        self.title.text = ""
        self.author.text = ""
        self.isi.text = ""
        self.hasil.text = result

class MyApp(App):
    def build(self):
        return MyGrid()

if __name__ == "__main__":
    MyApp().run()


import os
import torch
import numpy as np
from torch import nn, optim
from torch.utils.data import Dataset, DataLoader
from torch.autograd import Variable
from tensorboardX import SummaryWriter
from networks import torch_utils, basic_networks
from networks.conv_lstm_cell import ConvLSTMCell
from utils.dataset import KddDataset, random_split
from utils.eval import SMAPE

if __name__ == "__main__":
    # set manual seed
    torch.manual_seed(0)

    # define sequence_length, batch_size, channels, height, width
    T, T_PRED, B, C, H, W, NUM_CITY, NUM_AQ = 48, 24, 16, 5, 31, 21, 35, 3
    HIDDEN_SIZE = 32
    NUM_LAYERS = 1
    LEARNING_RATE = 1e-4
    MAX_EPOCH = 1000

    dataset = torch.load('data/dataset_bj.pt')
    train_set, validation_set = random_split(dataset, [3, 1])
    train_loader = DataLoader(train_set, batch_size=B, shuffle=True)
    validation_loader = DataLoader(validation_set, batch_size=B, shuffle=True)
    print('Size of train, validation: {}, {}'.format(
        len(train_set), len(validation_set)))

    print('Instantiate model')
    aq_lstm = nn.LSTM(input_size=NUM_CITY * NUM_AQ, hidden_size=HIDDEN_SIZE,
                      num_layers=NUM_LAYERS, batch_first=True)
    me_lstm = ConvLSTMCell(C, HIDDEN_SIZE)
    fusion = basic_networks.NNList([
        torch_utils.Flatten(),
        basic_networks.FC(
            input_dim=HIDDEN_SIZE + HIDDEN_SIZE * H * W,
            output_dim=T_PRED * NUM_CITY * NUM_AQ,
            hidden_dims=[],
        ),
    ])

    # print('Run on multiple gpus')
    aq_lstm = aq_lstm.cuda()
    me_lstm = me_lstm.cuda()
    fusion = fusion.cuda()
    models = [aq_lstm, me_lstm, fusion]

    print('Create a criterion and optimizer')
    loss_fn = nn.MSELoss()  # reduce=False)
    optimizer = optim.Adam(
        [params for model in models for params in model.parameters()], lr=LEARNING_RATE)

    print('Run for {MAX_EPOCH} epochs')
    writer = SummaryWriter()
    PLOT_EVERY = 1

    def run_batch(sample):
        B = sample[0].shape[0]
        aq, me, me_pred, y = sample[0].cuda(), sample[1].cuda(
        ), sample[2].cuda(), sample[3].cuda()
        me = torch.cat([me, me_pred], dim=1)
        # TODO this is not elegant
        aq[torch.isnan(aq)] = 0
        me[torch.isnan(me)] = 0
        ori_y = y.clone()
        y[torch.isnan(y)] = 0

        hidden = (Variable(torch.zeros(NUM_LAYERS, B, HIDDEN_SIZE)).cuda(),
                  Variable(torch.zeros(NUM_LAYERS, B, HIDDEN_SIZE)).cuda())
        aq_state = aq_lstm(aq, hidden)
        aq_feature = aq_state[0][:, -1]

        me_state = None
        for t in range(T):
            me_state = me_lstm(me[:, t], me_state)
        me_feature = me_state[0].view(B, -1)

        # compute predicted value
        # y_hat = fusion(aq_feature)
        y_hat = fusion(torch.cat([aq_feature, me_feature], dim=1))
        y_hat = y_hat.view(B, T_PRED, NUM_CITY * NUM_AQ)
        loss = loss_fn(y_hat, y)
        # nan_mask = torch.isnan(loss)
        # loss = torch.mean(loss[~nan_mask])

        ori_y = ori_y.view(B, T_PRED, NUM_CITY, NUM_AQ)
        y_hat = y_hat.view(B, T_PRED, NUM_CITY, NUM_AQ)
        smape = SMAPE(dataset.aq_mean + dataset.aq_std * ori_y.data,
                      dataset.aq_mean + dataset.aq_std * y_hat.data)
        return loss, smape

    for epoch in range(MAX_EPOCH):
        for sample_batched in train_loader:
            loss, smape = run_batch(sample_batched)

            print(' > Epoch {:2d} loss: {:.3f}'.format(epoch, loss.data[0]))

            # zero grad parameters
            for model in models:
                model.zero_grad()

            # compute new grad parameters through time!
            loss.backward()
            # for model in models:
            # for param in model.parameters():
            # if param.grad is None:
            # continue
            # print(int(torch.sum(torch.isnan(param.grad))))
            # print(int(torch.sum(torch.isnan(param.grad))) / int(np.prod(param.grad.shape)))
            # param.grad[torch.isnan(param.grad)] = 0

            # learning_rate step against the gradient
            optimizer.step()

        if epoch % PLOT_EVERY == 0:
            writer.add_scalar('train_loss', loss, epoch)
            writer.add_scalar('train_SMAPE', smape, epoch)

            validation_loss, validation_smape = \
                run_batch(iter(validation_loader).next())
            print(' > Epoch {:2d} validation loss: {:.3f}'.format(
                epoch, validation_loss.data[0]))
            writer.add_scalar('validation_loss',
                              validation_loss, epoch)
            writer.add_scalar('validation_SMAPE',
                              validation_smape, epoch)


# 2392 Интересная сумма
n=input()
c=[int(i) for i in n]
c.sort()
for i in range(1):
    if c[0]==0:
        if c[1]==0:
            c=[c[2],c[1],c[0]]
            print(int(n)*2)
        else:
            c=[c[1],c[0],c[2]]
            v_min=(str(c[0]),str(c[1]),str(c[2]))
            v_max=(str(c[2]),str(c[0]),str(c[1]))
            v1=int(''.join(v_min))
            v2=int(''.join(v_max))
            print(v1+v2)
    else:
        c_min=c
        c_max=c[::-1]
        our1=[str(i) for i in c_min]
        our2=[str(i) for i in c_max]
        w1=''.join(our1)
        w2=''.join(our2)
        print(int(w1)+int(w2))


import torch.nn as nn

from models.GeneralModel import GeneralModel
from utils.constants import *
from utils.model_utils import find_right_model

class CombinedClassifier(GeneralModel):

    def __init__(self,
                 hidden_dim, z_dim,
                 hidden_dim_vae, num_classes,
                 lstm_file, vae_files,
                 generator_loss,
                 generator_class,
                 dataset_options,
                 classifier_name, vaes_names,
                 # below: probably things we wont change
                 classifier_class='LSTMClassifier',
                 test_mode=False,
                 combined_weights_load = None,
                 combination_method='joint',
                 only_eval=True,
                 n_channels_in=(0), device="cpu", **kwargs):
        super(CombinedClassifier, self).__init__(n_channels_in, device, **kwargs)

        self.base_classifier = find_right_model(CLASS_DIR,
                                                classifier_class,
                                                n_channels_in=n_channels_in,
                                                num_classes=num_classes,
                                                device=device,
                                                hidden_dim=hidden_dim
                                                ).to(device)

        self.vae_classifier = find_right_model(CLASS_DIR,
                                               'VAEClassifier',
                                               generator_class=generator_class,
                                               generator_loss=generator_loss,
                                               vae_files=vae_files,
                                               vaes_names=vaes_names,
                                               device=device,
                                               n_channels_in=n_channels_in,
                                               hidden_dim=hidden_dim_vae,
                                               z_dim=z_dim,
                                               only_eval=only_eval,
                                               dataset_options=dataset_options,
                                               test_mode=test_mode
                                               ).to(device)

        if only_eval:
            self.base_classifier.eval()

        lstm_file = os.path.join(GITIGNORED_DIR, RESULTS_DIR, lstm_file)
        datamanager = DataManager(lstm_file)
        loaded = datamanager.load_python_obj(os.path.join('models', classifier_name))

        for state_dict in loaded.values():
            state_dict = state_dict
        self.base_classifier.load_state_dict(state_dict)

        # in case we wanna learn a weighted sum
        self.combination_method = combination_method

        if self.combination_method == 'learn_classifier':

            self.layers_lstm = nn.Sequential(
                nn.Linear(5, 5),
                nn.ReLU()
            )

            self.layers_vae = nn.Sequential(
                nn.Linear(5, 5),
                nn.ReLU()
            )

            self.shared = nn.Sequential(
                nn.Linear(10, 5),
                nn.Sigmoid()
            )

        elif self.combination_method == "learn_sum":

            self.W_classifier = nn.Parameter(torch.ones((num_classes,)) * 0.5)
            self.W_vaes = nn.Parameter(torch.ones((num_classes,)) * 0.5)
            self.W_classifier.requires_grad = True
            self.W_vaes.requires_grad = True

            if combined_weights_load is not None:
                weights_load = os.path.join(GITIGNORED_DIR, RESULTS_DIR, combined_weights_load)
                datamanager = DataManager(weights_load)
                loaded = datamanager.load_python_obj(os.path.join('models', 'finished'))

            for state_dict in loaded.values():
                state_dict = state_dict
            self.load_state_dict(state_dict)

            print(self.W_classifier)
            print(self.W_vaes)

    def forward(self, inp, targets, lengths, inp_sentence, step):
        inp2, targets2, lengths2 = inp_sentence
        out_base = self.base_classifier.forward(inp.detach(), lengths.detach())  # need to put through softmax
        out_base_class_scores = nn.functional.softmax(*out_base, dim=-1).detach()

        _, _, vae_loss = self.vae_classifier.forward(inp2, lengths2, step, targets2)
        vae_loss = torch.stack(vae_loss)
        vae_likelihood = - vae_loss
        vae_score = nn.Softmax(dim=-1)(vae_likelihood)

        if 'joint' in self.combination_method:
            combined_score = self.joint_probability(out_base_class_scores, vae_score)
        elif 'learn' in self.combination_method:
            combined_score = self.weighted_sum(out_base_class_scores, vae_score)
        else:
            raise Exception

        return combined_score, (out_base_class_scores, vae_likelihood)

        # todo | keep in mind that scores should be as if they're probabilities, meaning for
        # todo | classification we take argmax and classify directly

    def joint_probability(self, pxy, px):
        approach_px = torch.exp(px)
        return pxy * approach_px

    def weighted_sum(self, classifier_score, vaes_score):  # TODO: give elbo or recons or (regul??) ??
        if self.combination_method == "learn_classifier":
            return self.shared.forward(torch.cat((self.layers_lstm.forward(classifier_score.detach().squeeze()),
                                                  self.layers_vae.forward(vaes_score.detach())), dim=0))

        elif self.combination_method == "learn_sum":
            return self.W_classifier * classifier_score.detach() + self.W_vaes * vaes_score.detach()


from PyQt5.QtCore import QRegularExpression, pyqtSignal
from PyQt5.QtGui import QIcon, QRegularExpressionValidator, QValidator
from PyQt5.QtWidgets import QLineEdit,QHBoxLayout, QComboBox, QToolButton,QWidget

class SelectionWidget(QWidget):
    completed = pyqtSignal(bool)

    def __init__(self, items, parent=None):
        QWidget.__init__(self, parent)
        #Main Layout is a horizontal box
        self.setLayout(QHBoxLayout())

        #Create the drop down menu and fill it with the table names
        self.combobox = QComboBox(self)
        self.combobox.addItems(items)
        self.layout().addWidget(self.combobox)

        self.le = QLineEdit(self)
        self.le.setValidator(QRegularExpressionValidator(QRegularExpression("^([0-9])+(,[0-9]+)*$"), self))
        self.le.textChanged.connect(self.check_state)
        self.layout().addWidget(self.le)

        btnDelete = QToolButton(self)
        btnDelete.setIcon(QIcon.fromTheme("edit-delete"))
        self.layout().addWidget(btnDelete)
        btnDelete.clicked.connect(self.deleteLater)

    def getRows(self):
        try:
            return self.combobox.currentText(), [int(el) for el in self.le.text().split(",")]
        except Exception as p:
            print("error P: {}".format(p))

    def check_state(self, text):
        sender = self.sender()
        validator = sender.validator()
        state = validator.validate(text, 0)[0]
        if state == QValidator.Acceptable:
            color = '#c4df9b'  # green
            self.completed.emit(True)
        elif state == QValidator.Intermediate:
            color = '#fff79a'  # yellow
            self.completed.emit(False)
        else:
            color = '#f6989d'  # red
            self.completed.emit(True)
        sender.setStyleSheet('QLineEdit { background-color: %s }' % color)