import functools
import logging
import os
from itertools import permutations, combinations
from collections import defaultdict
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import logout as base_logout
from django.core.exceptions import PermissionDenied
from django.db.models import Count, Q
from django.http import HttpResponseForbidden, JsonResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.utils.functional import cached_property
from django.views.generic import TemplateView, View
from dal import autocomplete
from rest_framework import status
from rest_framework.generics import ListAPIView
from rest_framework.pagination import PageNumberPagination
from rest_framework.permissions import BasePermission
from rest_framework.response import Response
from social_django.models import UserSocialAuth
from isle.forms import CreateTeamForm, AddUserForm
from isle.models import Event, EventEntry, EventMaterial, User, Trace, Team, EventTeamMaterial, EventOnlyMaterial, \
    Attendance
from isle.serializers import AttendanceSerializer
from isle.utils import refresh_events_data, get_allowed_event_type_ids, update_check_ins_for_event, set_check_in

def login(request):
    return render(request, 'login.html', {'next': request.GET.get('next', reverse('index'))})

def logout(request):
    return base_logout(request, next_page='index')

@method_decorator(login_required, name='dispatch')
class Index(TemplateView):
    """
    все эвенты (доступные пользователю)
    """
    template_name = 'index.html'
    DATE_FORMAT = '%Y-%m-%d'

    def get_context_data(self, **kwargs):
        date = self.get_date()
        objects = self.get_events()
        ctx = {
            'objects': objects,
            'date': date.strftime(self.DATE_FORMAT) if date else None,
            'sort_asc': self.is_asc_sort(),
        }
        if self.request.user.is_assistant:
            fdict = {
                'initiator__in': User.objects.filter(is_assistant=True).values_list('id', flat=True)
            }
            ctx.update({
                'total_elements': EventMaterial.objects.count() +
                                  EventTeamMaterial.objects.count() +
                                  EventOnlyMaterial.objects.count(),
                'today_elements': EventMaterial.objects.filter(event__in=objects).count() +
                                  EventTeamMaterial.objects.filter(event__in=objects).count() +
                                  EventOnlyMaterial.objects.filter(event__in=objects).count(),
                'total_elements_user': EventMaterial.objects.exclude(initiator__isnull=True).exclude(**fdict).count() +
                                       EventTeamMaterial.objects.exclude(initiator__isnull=True).exclude(**fdict).count(),
                'today_elements_user': EventMaterial.objects.exclude(initiator__isnull=True).exclude(**fdict).filter(event__in=objects).count() +
                                       EventTeamMaterial.objects.exclude(initiator__isnull=True).exclude(**fdict).filter(event__in=objects).count(),
            })
            if self.request.user.is_assistant:
                enrollments = dict(EventEntry.objects.values_list('event_id').annotate(cnt=Count('user_id')))
                check_ins = dict(EventEntry.objects.filter(is_active=True).values_list('event_id')
                                 .annotate(cnt=Count('user_id')))
                for obj in objects:
                    obj.prop_enrollments = enrollments.get(obj.id, 0)
                    obj.prop_checkins = check_ins.get(obj.id, 0)
        else:
            user_materials_num = dict(EventMaterial.objects.filter(event__in=objects, user=self.request.user)
                                      .values_list('event_id').annotate(cnt=Count('user_id')))
            teams = Team.objects.filter(event__in=objects, users=self.request.user).values_list('id', flat=True)
            team_materials_num = dict(EventTeamMaterial.objects.filter(event__in=objects, team_id__in=teams)
                                      .values_list('event_id').annotate(cnt=Count('team_id')))
            event_num, trace_num = 0, 0
            for obj in objects:
                obj.user_materials_num = user_materials_num.get(obj.id, 0)
                obj.team_materials_num = team_materials_num.get(obj.id, 0)
                if obj.user_materials_num or obj.team_materials_num:
                    event_num += 1
                trace_num += (obj.user_materials_num + obj.team_materials_num)
            ctx.update({'event_num': event_num, 'trace_num': trace_num})
        return ctx

    def get_date(self):
        try:
            date = timezone.datetime.strptime(self.request.GET.get('date'), self.DATE_FORMAT).date()
        except:
            if not self.request.user.is_assistant:
                return
            date = timezone.localtime(timezone.now()).date()
        return date

    def get_events(self):
        if self.request.user.is_assistant:
            events = Event.objects.filter(is_active=True)
        else:
            events = Event.objects.filter(id__in=EventEntry.objects.filter(user=self.request.user).
                                          values_list('event_id', flat=True))
        if settings.VISIBLE_EVENT_TYPES:
            events = events.filter(event_type_id__in=get_allowed_event_type_ids())
        date = self.get_date()
        if date:
            min_dt = timezone.make_aware(timezone.datetime.combine(date, timezone.datetime.min.time()))
            max_dt = min_dt + timezone.timedelta(days=1)
            events = events.filter(dt_start__gte=min_dt, dt_start__lt=max_dt)
        events = events.order_by('{}dt_start'.format('' if self.is_asc_sort() else '-'))
        return events

    def is_asc_sort(self):
        return self.request.GET.get('sort') != 'desc'

class GetEventMixin:
    @cached_property
    def event(self):
        return get_object_or_404(Event, uid=self.kwargs['uid'])

    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

class GetEventMixinWithAccessCheck(GetEventMixin):
    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return HttpResponseRedirect('{}?next={}'.format(reverse('login'), request.get_full_path()))
        if request.user.is_assistant or EventEntry.objects.filter(user=request.user, event=self.event).exists():
            return super().dispatch(request, *args, **kwargs)
        return render(request, 'to_xle.html', {
            'link': getattr(settings, 'XLE_URL', 'https://xle.2035.university/feedback'),
            'event': self.event,
        })

def get_event_participants(event):
    users = EventEntry.objects.filter(event=event).values_list('user_id')
    return User.objects.filter(id__in=users).order_by('last_name', 'first_name', 'second_name')

class EventView(GetEventMixinWithAccessCheck, TemplateView):
    """
    Просмотр статистики загрузок материалов по эвентам
    """
    template_name = 'event_view.html'

    def get_context_data(self, **kwargs):
        users = list(get_event_participants(self.event))
        user_entry = [i for i in users if i.id == self.request.user.id]
        if user_entry:
            users = user_entry + [i for i in users if i.id != self.request.user.id]
        check_ins = set(EventEntry.objects.filter(event=self.event, is_active=True).values_list('user_id', flat=True))
        attends = set(Attendance.objects.filter(event=self.event, is_confirmed=True).values_list('user_id', flat=True))
        chat_bot_added = set(Attendance.objects.filter(event=self.event, confirmed_by_system=Attendance.SYSTEM_CHAT_BOT)
                             .values_list('user_id', flat=True))
        user_teams = []
        if not self.request.user.is_assistant:
            num = dict(EventMaterial.objects.filter(event=self.event, user__in=users, is_public=True).
                       values_list('user_id').annotate(num=Count('event_id')))
            num[self.request.user.id] = EventMaterial.objects.filter(event=self.event, user=self.request.user).count()
            user_teams = list(Team.objects.filter(event=self.event, users=self.request.user).values_list('id', flat=True))
        else:
            num = dict(EventMaterial.objects.filter(event=self.event, user__in=users).
                       values_list('user_id').annotate(num=Count('event_id')))
        can_delete = set(EventEntry.objects.filter(event=self.event, added_by_assistant=True).
                         values_list('user_id', flat=True))
        for u in users:
            u.materials_num = num.get(u.id, 0)
            u.checked_in = u.id in check_ins
            u.attend = u.id in attends
            u.can_delete = u.id in can_delete
            u.added_by_chat_bot = u.id in chat_bot_added
        return {
            'students': users,
            'event': self.event,
            'teams': Team.objects.filter(event=self.event).select_related('creator').order_by('name'),
            'user_teams': user_teams,
            'event_entry': EventEntry.objects.filter(event=self.event, user=self.request.user).first(),
        }

class BaseLoadMaterials(GetEventMixinWithAccessCheck, TemplateView):
    template_name = 'load_materials.html'
    material_model = None

    def get_context_data(self, **kwargs):
        data = super().get_context_data(**kwargs)
        data.update({
            'traces': self.get_traces_data(),
            'allow_file_upload': getattr(settings, 'ALLOW_FILE_UPLOAD', True),
            'max_size': settings.MAXIMUM_ALLOWED_FILE_SIZE,
            'max_uploads': settings.MAX_PARALLEL_UPLOADS,
            'event': self.event,
            'can_upload': self.can_upload(),
            'can_set_public': self._can_set_public(),
        })
        return data

    def can_upload(self):
        return self.request.user.is_assistant

    def _can_set_public(self):
        return False

    def get_traces_data(self):
        traces = self.event.get_traces()
        result = []
        links = defaultdict(list)
        for item in self.get_materials():
            links[item.trace_id].append(item)
        for trace in traces:
            result.append({'trace': trace, 'links': links.get(trace.id, [])})
        return result

    def post(self, request, *args, **kwargs):
        resp = self.check_post_allowed(request)
        if resp is not None:
            return resp
        try:
            trace_id = int(request.POST.get('trace_name'))
        except (ValueError, TypeError):
            return JsonResponse({}, status=400)
        if not trace_id or not trace_id in [i.id for i in self.event.get_traces()]:
            return JsonResponse({}, status=400)
        if 'add_btn' in request.POST:
            return self.add_item(request)
        return self.delete_item(request)

    def check_post_allowed(self, request):
        if not self.event.is_active or not self.can_upload():
            return JsonResponse({}, status=403)

    def delete_item(self, request):
        material_id = request.POST.get('material_id')
        if not material_id or not material_id.isdigit():
            return JsonResponse({}, status=400)
        trace = Trace.objects.filter(id=request.POST['trace_name']).first()
        if not trace:
            return JsonResponse({}, status=400)
        return self._delete_item(trace, material_id)

    def add_item(self, request):
        trace = Trace.objects.filter(id=request.POST['trace_name']).first()
        if not trace:
            return JsonResponse({}, status=400)
        data = self.get_material_fields(trace, request)
        url = request.POST.get('url_field')
        file_ = request.FILES.get('file_field')
        if bool(file_) == bool(url):
            return JsonResponse({}, status=400)
        if url:
            data['url'] = url
        data['initiator'] = request.user.unti_id
        material = self.material_model.objects.create(**data)
        if file_:
            material.file.save(self.make_file_path(file_.name), file_)
        resp = {
            'material_id': material.id,
            'url': material.get_url(),
            'name': material.get_name(),
            'comment': getattr(material, 'comment', ''),
            'is_public': getattr(material, 'is_public', True),
            'can_set_public': self._can_set_public()
        }
        if self.extra_context and self.extra_context.get('team_upload'):
            resp['uploader_name'] = request.user.fio
        return JsonResponse(resp)

    def get_material_fields(self, trace, request):
        return {}

    def make_file_path(self, fn):
        return fn

class LoadMaterials(BaseLoadMaterials):
    """
    Просмотр/загрузка материалов по эвенту
    """
    material_model = EventMaterial
    extra_context = {'with_public_checkbox': True}

    def _can_set_public(self):
        return self.request.user.unti_id == int(self.kwargs['unti_id'])

    def can_upload(self):
        return self.request.user.is_assistant or int(self.kwargs['unti_id']) == self.request.user.unti_id

    def get_materials(self):
        if self.can_upload():
            return EventMaterial.objects.filter(event=self.event, user=self.user)
        return EventMaterial.objects.filter(event=self.event, user=self.user, is_public=True)

    @cached_property
    def user(self):
        return get_object_or_404(User, unti_id=self.kwargs['unti_id'])

    def _delete_item(self, trace, material_id):
        material = EventMaterial.objects.filter(
            event=self.event, user=self.user, trace=trace, id=material_id
        ).first()
        if not material:
            return JsonResponse({}, status=400)
        material.delete()
        logging.warning('User %s has deleted file %s for user %s' %
                        (self.request.user.username, material.get_url(), self.user.username))
        return JsonResponse({})

    def add_item(self, request):
        if not EventEntry.objects.filter(event=self.event, user=self.user).exists():
            return JsonResponse({}, status=400)
        return super().add_item(request)

    def get_material_fields(self, trace, request):
        public = self._can_set_public() and request.POST.get('is_public') in ['on']
        return dict(event=self.event, user=self.user, trace=trace, is_public=public,
                    comment=request.POST.get('comment', ''))

    def make_file_path(self, fn):
        return os.path.join(self.event.uid, str(self.user.unti_id), fn)

class LoadTeamMaterials(BaseLoadMaterials):
    """
    Просмотр/загрузка командных материалов по эвенту
    """
    extra_context = {'with_comment_input': True, 'team_upload': True, 'show_owners': True}
    material_model = EventTeamMaterial

    def get_context_data(self, **kwargs):
        data = super().get_context_data(**kwargs)
        users = self.team.users.order_by('last_name', 'first_name', 'second_name')
        num = dict(EventMaterial.objects.filter(event=self.event, user__in=users).
                   values_list('user_id').annotate(num=Count('event_id')))
        for u in users:
            u.materials_num = num.get(u.id, 0)
        data.update({'students': users, 'event': self.event, 'team_name': getattr(self.team, 'name', ''),
                     'team': self.team})
        return data

    @cached_property
    def team(self):
        return get_object_or_404(Team, id=self.kwargs['team_id'])

    def get_materials(self):
        qs = EventTeamMaterial.objects.filter(event=self.event, team=self.team).prefetch_related('owners')
        users = {i.unti_id: i for i in User.objects.filter(unti_id__in=filter(None, [j.initiator for j in qs]))}
        for item in qs:
            item.initiator_user = users.get(item.initiator)
            if not self.request.user.is_assistant:
                item.is_owner = self.request.user in item.owners.all()
                item.ownership_url = reverse('team-material-owner', kwargs={
                    'uid': self.event.uid, 'material_id': item.id, 'team_id': self.team.id})
        return qs

    def can_upload(self):
        # командные файлы загружает ассистент или участники этой команды
        return self.request.user.is_assistant or self.team.users.filter(id=self.request.user.id).exists()

    def post(self, request, *args, **kwargs):
        # загрузка и удаление файлов доступны только для эвентов, доступных для оцифровки, и по
        # командам, сформированным в данном эвенте
        if not self.event.is_active or not (self.request.user.is_assistant or
                Team.objects.filter(event=self.event, id=self.kwargs['team_id']).exists()):
            return JsonResponse({}, status=403)
        try:
            trace_id = int(request.POST.get('trace_name'))
        except (ValueError, TypeError):
            return JsonResponse({}, status=400)
        if not trace_id or not trace_id in [i.id for i in self.event.get_traces()]:
            return JsonResponse({}, status=400)
        if 'add_btn' in request.POST:
            return self.add_item(request)
        return self.delete_item(request)

    def check_post_allowed(self, request):
        # загрузка и удаление файлов доступны только для эвентов, доступных для оцифровки, и по
        # командам, сформированным в данном эвенте
        if not super().check_post_allowed(request) or not \
                Team.objects.filter(event=self.event, id=self.kwargs['team_id']).exists():
            return JsonResponse({}, status=403)

    def _delete_item(self, trace, material_id):
        material = EventTeamMaterial.objects.filter(
            event=self.event, team=self.team, trace=trace, id=material_id
        ).first()
        if not material:
            return JsonResponse({}, status=400)
        material.delete()
        logging.warning('User %s has deleted file %s for team %s' %
                        (self.request.user.username, material.get_url(), self.team.id))
        return JsonResponse({})

    def make_file_path(self, fn):
        return os.path.join(self.event.uid, str(self.team.team_name), fn)

    def get_material_fields(self, trace, request):
        return dict(event=self.event, team=self.team, trace=trace, comment=request.POST.get('comment', ''),
                    confirmed=self.request.user.is_assistant)

class LoadEventMaterials(BaseLoadMaterials):
    """
    Загрузка материалов мероприятия
    """
    material_model = EventOnlyMaterial
    extra_context = {'with_comment_input': True, 'show_owners': True}

    def get_materials(self):
        qs = EventOnlyMaterial.objects.filter(event=self.event).prefetch_related('owners')
        for item in qs:
            if not self.request.user.is_assistant:
                item.is_owner = self.request.user in item.owners.all()
                item.ownership_url = reverse('event-material-owner', kwargs={
                    'uid': self.event.uid, 'material_id': item.id})
        return qs

    def _delete_item(self, trace, material_id):
        material = EventOnlyMaterial.objects.filter(
            event=self.event, trace=trace, id=material_id
        ).first()
        if not material:
            return JsonResponse({}, status=400)
        material.delete()
        logging.warning('User %s has deleted file %s for event %s' %
                        (self.request.user.username, material.get_url(), self.event.uid))
        return JsonResponse({})

    def make_file_path(self, fn):
        return os.path.join(self.event.uid, fn)

    def get_material_fields(self, trace, request):
        return dict(event=self.event, trace=trace, comment=request.POST.get('comment', ''))

class RefreshDataView(View):
    def get(self, request, uid=None):
        if not request.user.is_assistant:
            success = False
        else:
            if uid:
                if not Event.objects.filter(uid=uid).exists():
                    success = False
                else:
                    success = refresh_events_data(force=True, refresh_participants=True, refresh_for_events=[uid])
            else:
                success = refresh_events_data(force=True)
        return JsonResponse({'success': bool(success)})

class CreateTeamView(GetEventMixin, TemplateView):
    template_name = 'create_team.html'

    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated or not (request.user.is_assistant or
                EventEntry.objects.filter(event=self.event, user=request.user).exists()):
            return HttpResponseForbidden()
        return super().dispatch(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        users = self.get_available_users()
        return {'students': users, 'event': self.event}

    def get_available_users(self):
        return get_event_participants(self.event)

    def post(self, request, uid=None):
        form = CreateTeamForm(data=request.POST, event=self.event, users_qs=self.get_available_users(),
                              creator=request.user)
        if not form.is_valid():
            return JsonResponse({}, status=400)
        form.save()
        return JsonResponse({'redirect': reverse('event-view', kwargs={'uid': self.event.uid})})

class RefreshCheckInView(GetEventMixin, View):
    """
    Обновление чекинов всех пользователей определенного мероприятия из ILE
    или обновление чекина одного пользователя в ILE
    """
    def dispatch(self, request, *args, **kwargs):
        if request.user.is_authenticated and request.user.is_assistant:
            return super().dispatch(request, *args, **kwargs)
        return HttpResponseForbidden()

    def get(self, request, uid=None):
        if not self.event.ext_id:
            return JsonResponse({'success': False})
        return JsonResponse({'success': bool(update_check_ins_for_event(self.event))})

    # def post(self, request, uid=None):
    #     if not self.event.ext_id:
    #         return JsonResponse({'success': False})
    #     user_id = request.POST.get('user_id')
    #     if not user_id or 'status' not in request.POST:
    #         return JsonResponse({}, status=400)
    #     user = User.objects.filter(id=user_id).first()
    #     if not user or not EventEntry.objects.filter(event=self.event, user=user).exists():
    #         return JsonResponse({}, status=400)
    #     status = request.POST['status'] in ['true', '1', True]
    #     result = set_check_in(self.event, user, status)
    #     if result:
    #         EventEntry.objects.filter(event=self.event, user=user).update(is_active=True)
    #         Attendance.objects.update_or_create(
    #             event=self.event, user=user,
    #             defaults={
    #                 'confirmed_by_user': request.user,
    #                 'is_confirmed': True,
    #                 'confirmed_by_system': Attendance.SYSTEM_UPLOADS,
    #             }
    #         )
    #         logging.info('User %s has checked in user %s on event %s' %
    #                      (request.user.username, user.username, self.event.id))
    #     return JsonResponse({'success': result})

class AddUserToEvent(GetEventMixin, TemplateView):
    """
    Добавить пользователя на мероприятие вручную
    """
    template_name = 'add_user.html'

    def dispatch(self, request, *args, **kwargs):
        if request.user.is_authenticated and request.user.is_assistant:
            return super().dispatch(request, *args, **kwargs)
        return HttpResponseForbidden()

    def get_context_data(self, **kwargs):
        data = super().get_context_data(**kwargs)
        data.update({'event': self.event, 'form': AddUserForm(event=self.event)})
        return data

    def post(self, request, uid=None):
        form = AddUserForm(data=request.POST, event=self.event)
        if form.is_valid():
            user = form.cleaned_data['user']
            EventEntry.all_objects.update_or_create(
                user=user, event=self.event,
                defaults={'added_by_assistant': True, 'check_in_pushed': False, 'deleted': False}
            )
            Attendance.objects.update_or_create(
                event=self.event, user=user,
                defaults={
                    'confirmed_by_user': request.user,
                    'is_confirmed': True,
                    'confirmed_by_system': Attendance.SYSTEM_UPLOADS,
                }
            )
            logging.info('User %s added user %s to event %s' % (request.user.username, user.username, self.event.id))
            return redirect('event-view', uid=self.event.uid)
        else:
            return render(request, self.template_name, {'event': self.event, 'form': form})

class RemoveUserFromEvent(GetEventMixin, View):
    def post(self, request, uid=None):
        if not request.user.is_authenticated or not request.user.is_assistant:
            return JsonResponse({}, status=403)
        try:
            entry = EventEntry.objects.get(event=self.event, user_id=request.POST.get('user_id'),
                                           added_by_assistant=True)
        except (TypeError, ValueError, EventEntry.DoesNotExist):
            return JsonResponse({}, status=404)
        EventEntry.objects.filter(event=self.event, user_id=request.POST.get('user_id')).update(deleted=True)
        Attendance.objects.filter(event=self.event, user_id=request.POST.get('user_id')).delete()
        logging.warning('User %s removed user %s from event %s' %
                        (request.user.username, entry.user.username, entry.event.uid))
        return JsonResponse({})

class UserAutocomplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        event_id = self.forwarded.get('event_id')
        if not self.request.user.is_authenticated or not self.request.user.is_assistant or not event_id:
            return User.objects.none()
        qs = User.objects.filter(is_assistant=False).exclude(
            id__in=EventEntry.objects.filter(event_id=event_id).values_list('user_id', flat=True)
        ).filter(id__in=UserSocialAuth.objects.all().values_list('user__id', flat=True))
        if self.q:
            if len(self.q.split()) == 1:
                qs = qs.filter(
                    Q(email__icontains=self.q) | Q(username__icontains=self.q) |
                    Q(last_name__icontains=self.q) | Q(first_name__icontains=self.q) |
                    Q(second_name__icontains=self.q)
                )
            else:
                filters = []
                q_parts = self.q.split()
                fields = ['last_name', 'first_name', 'second_name']
                for p_len in range(1, min(len(fields), len(q_parts)) + 1):
                    indexes = filter(lambda c: c[0] == 0, combinations(range(len(q_parts)), p_len))
                    ranges = (zip(idxs, idxs[1:] + (None,)) for idxs in indexes)
                    parts_combs = [[" ".join(q_parts[i:j]) for i, j in r] for r in ranges]
                    for p in permutations(fields, p_len):
                        filters.append(functools.reduce(lambda x, y: x | y,
                                              (Q(**{k: v for k, v in zip(p, parts)}) for parts in parts_combs)))
                qs = qs.filter(functools.reduce(lambda x, y: x | y, filters))
        return qs

    def get_result_label(self, result):
        full_name = ' '.join(filter(None, [result.last_name, result.first_name, result.second_name]))
        return '%s, (%s)' % (full_name, result.leader_id)

class Paginator(PageNumberPagination):
    page_size = 20

class ApiPermission(BasePermission):
    def has_permission(self, request, view):
        if request.method == 'OPTIONS':
            return True
        api_key = getattr(settings, 'API_KEY', '')
        key = request.META.get('HTTP_X_API_KEY')
        if key and api_key and key == api_key:
            return True
        return False

class AttendanceApi(ListAPIView):
    """
    **Описание**

        Получение списка присутствовавших на мероприятии или добавление/обновление объекта присутствия.
        В запросе должен присутствовать хедер X-API-KEY

    **Пример get-запроса**

        GET /api/attendance/

    **Пример ответа**

        * {
            "count": 3, // общее количество объектов
            "next": null, // полный url следующей страницы (если есть)
            "previous": null, // полный url предыдущей страницы (если есть)
            "results": [
                {
                    "unti_id": 125, // id пользователя в UNTI SSO
                    "event_id": 2448, // id мероприятия в LABS
                    "created_on": "2018-07-15T07:14:04+10:00", // дата создания объекта
                    "updated_on": "2018-07-15T07:14:04+10:00", // дата обновления объекта
                    "is_confirmed": true, // присутствие подтверждено
                    "confirmed_by_user": 1, // id пользователя подтвердившего присутствие в UNTI SSO
                    "confirmed_by_system": "uploads", // кем подтверждено uploads или chat_bot
                    "run_id": 1405, // id прогона в LABS
                    "activity_id": 439 // id активити в LABS
                },
                ...
          }

    **Пример post-запроса**

    POST /api/attendance/{
            "is_confirmed": true,
            "user_id": 1,
            "event_id": 1,
            "confirmed_by_user": 1,
        }

    **Параметры post-запроса**

        * is_confirmed: подтверждено или нет, boolean
        * user_id: id пользователя в UNTI SSO, integer
        * event_id: id мероприятия в LABS, integer
        * confirmed_by_user: id пользователя в UNTI SSO, который подтвердил присутствие, integer или null,
          необязательный параметр

    **Пример ответа**

         * код 200, словарь с параметрами объекта как при get-запросе, если запрос прошел успешно
         * код 400, если не хватает параметров в запросе
         * код 403, если не указан хедер X-API-KEY или ключ неверен
         * код 404, если не найден пользователь или мероприятие из запроса

    """

    serializer_class = AttendanceSerializer
    pagination_class = Paginator
    permission_classes = (ApiPermission, )

    def get_queryset(self):
        qs = Attendance.objects.order_by('id')
        unti_id = self.request.query_params.get('unti_id')
        if unti_id and unti_id.isdigit():
            qs = qs.filter(user__unti_id=unti_id)
        return qs

    def post(self, request):
        is_confirmed = request.data.get('is_confirmed')
        user_id = request.data.get('user_id')
        event_id = request.data.get('event_id')
        confirmed_by = request.data.get('confirmed_by_user')
        if is_confirmed is None or not user_id or not event_id:
            return Response({'error': 'request should contain is_confirmed, user_id and event_id parameters'},
                            status=status.HTTP_400_BAD_REQUEST)
        try:
            user = User.objects.get(unti_id=user_id)
        except (User.DoesNotExist, TypeError):
            return Response({'error': 'user does not exist'}, status=status.HTTP_404_NOT_FOUND)
        try:
            event = Event.objects.get(ext_id=event_id)
        except (Event.DoesNotExist, TypeError):
            return Response({'error': 'event does not exist'}, status=status.HTTP_404_NOT_FOUND)
        if confirmed_by is not None:
            try:
                confirmed_by = User.objects.get(unti_id=confirmed_by)
            except (ValueError, TypeError, User.DoesNotExist):
                return Response({'error': 'user does not exist'}, status=status.HTTP_404_NOT_FOUND)
        a = Attendance.objects.update_or_create(
            user=user, event=event,
            defaults={
                'confirmed_by_user': confirmed_by,
                'confirmed_by_system': Attendance.SYSTEM_CHAT_BOT,
                'is_confirmed': is_confirmed,
            }
        )[0]
        EventEntry.all_objects.update_or_create(event=event, user=user,
                                                defaults={'deleted': False, 'added_by_assistant': False})
        logging.info('AttendanceApi request: %s' % request.data)
        return Response(self.serializer_class(instance=a).data)

class UpdateAttendanceView(GetEventMixin, View):
    def post(self, request, uid=None):
        user_id = request.POST.get('user_id')
        if not user_id or 'status' not in request.POST:
            return JsonResponse({}, status=400)
        user = User.objects.filter(id=user_id).first()
        if not request.user.is_assistant:
            return JsonResponse({}, status=400)
        is_confirmed = request.POST.get('status') == 'true'
        Attendance.objects.update_or_create(
            event=self.event, user=user,
            defaults={
                'confirmed_by_user': request.user,
                'is_confirmed': is_confirmed,
                'confirmed_by_system': Attendance.SYSTEM_UPLOADS,
            }
        )
        logging.info('User %s has checked in user %s on event %s' %
                     (request.user.username, user.username, self.event.id))
        print('User %s has changed attendance for user %s on event %s to %s' %
                     (request.user.username, user.username, self.event.id, is_confirmed))
        return JsonResponse({'success': True})

@method_decorator(login_required, name='dispatch')
class IsMaterialPublic(GetEventMixin, View):
    def post(self, request, uid=None):
        try:
            trace = EventMaterial.objects.get(id=request.POST.get('trace_id'))
        except (EventMaterial.DoesNotExist, ValueError, TypeError):
            return JsonResponse({}, status=404)
        if trace.user != request.user:
            return JsonResponse({}, status=403)
        is_public = request.POST.get('is_public') in ['true', 'True']
        EventMaterial.objects.filter(id=trace.id).update(is_public=is_public)
        return JsonResponse({'is_public': is_public})

class ConfirmTeamMaterial(GetEventMixin, View):
    def post(self, request, uid=None, team_id=None):
        if not request.user.is_authenticated or not request.user.is_assistant:
            return JsonResponse({}, status=403)
        try:
            team = Team.objects.get(event=self.event, id=team_id)
            confirmed = EventTeamMaterial.objects.filter(team=team, id=request.POST.get('material_id')).\
                update(confirmed=True)
            assert confirmed
            logging.info('User %s confirmed team %s upload %s' %
                         (request.user.username, team.id, request.POST.get('material_id')))
        except (Team.DoesNotExist, EventTeamMaterial.DoesNotExist, ValueError, TypeError, AssertionError):
            return JsonResponse({}, status=404)
        return JsonResponse({})

class ConfirmTeamView(GetEventMixin, View):
    def post(self, request, uid=None):
        if not request.user.is_authenticated or not request.user.is_assistant:
            return JsonResponse({}, status=403)
        try:
            assert Team.objects.filter(event=self.event, id=request.POST.get('team_id')).update(confirmed=True)
            logging.info('User %s confirmed team %s' % (request.user.username, request.POST.get('team_id')))
        except (Team.DoesNotExist, TypeError, ValueError, AssertionError):
            return JsonResponse({}, status=404)
        return JsonResponse({})

class BaseOwnershipChecker(GetEventMixin, View):
    def post(self, request, **kwargs):
        if request.user.is_assistant or not EventEntry.objects.filter(event=self.event, user=request.user):
            return JsonResponse({}, status=403)
        material = self.get_material()
        confirm = request.POST.get('confirm')
        if confirm not in ['true', 'false']:
            return JsonResponse({}, status=400)
        confirm = confirm == 'true'
        if confirm:
            material.owners.add(request.user)
        else:
            material.owners.remove(request.user)
        return JsonResponse({'is_owner': confirm, 'owners': ', '.join(material.get_owners())})

class TeamMaterialOwnership(BaseOwnershipChecker):
    def get_material(self):
        return get_object_or_404(EventTeamMaterial, id=self.kwargs['material_id'], event=self.event,
                                 team_id=self.kwargs['team_id'])

class EventMaterialOwnership(BaseOwnershipChecker):
    def get_material(self):
        return get_object_or_404(EventOnlyMaterial, id=self.kwargs['material_id'], event=self.event)

class ApproveTextEdit(View):
    def post(self, request, event_entry_id=None):
        print(request.POST)
        if not request.user.is_authenticated or not event_entry_id:
            return JsonResponse({}, status=403)
        try:
            event_entry = EventEntry.objects.get(id=event_entry_id)
            event_entry.approve_text = request.POST.get('approve_text')
            event_entry.save()
        except EventEntry.DoesNotExist:
            return JsonResponse({}, status=404)
        return JsonResponse({})


import argparse
import json
import sys

from omero.gateway import BlitzGateway
from omero.cli import cli_login
from omero.model import StatsInfoI
from omero.rtypes import rdouble

# For an Image (ID), set min/max values for channel stats
# Usage: python set_channel_minmax.py 3453 '{"0":[0,2000], "1":[1, 1100]}'

def main(argv):
    parser = argparse.ArgumentParser()
    parser.add_argument('image', type=int, help='Image ID')
    parser.add_argument('minmax', help=(
        'Channel min/max values as JSON {"0":[0,100], "1":[1, 110]}'))
    args = parser.parse_args(argv)

    with cli_login() as cli:
        conn = BlitzGateway(client_obj=cli._client)

        image_id = args.image
        minmax_vals = json.loads(args.minmax)
        image = conn.getObject("Image", image_id)

        # Set statsInfo min & max
        for index, ch in enumerate(image.getChannels(noRE=True)):
            if str(index) in minmax_vals:
                minmax = minmax_vals[str(index)]
            else:
                continue
            si = ch.getStatsInfo()
            if si is None:
                si = StatsInfoI()
            else:
                si = si._obj
            if minmax[0] is not None:
                si.globalMin = rdouble(minmax[0])
            if minmax[1] is not None:
                si.globalMax = rdouble(minmax[1])
            ch._obj.statsInfo = si
            ch.save()

if __name__ == '__main__':
    main(sys.argv[1:])


import os, re

# execute command, and return the output
def execCmd(cmd):
    r = os.popen(cmd)
    text = r.read()
    r.close()
    return text

# write "data" to file-filename
def writeFile(filename, data):
    f = open(filename, "w")
    f.write(data)
    f.close()

if __name__ == '__main__':

    k = 0
    for line in open("random_nd.ltl"):
        cmdLtl2tgba = "ltl2tgba -f \"" + line + "\" --output=ltlaut/aut" + str(k) + ".hoa"
        cmdSpot = "seminator --complement=spot ltlaut/aut" + str(k) + ".hoa"
        cmdPldi = "seminator --complement=pldi ltlaut/aut" + str(k) + ".hoa"
        cmdNsbc = "seminator --complement=nsbc ltlaut/aut" + str(k) + ".hoa"
        cmdAutfiltCom = "autfilt ltlaut/aut" + str(k) + ".hoa --complement --output=true/tcom" + str(k) + ".hoa"
        cmdAutfiltEquiv = "autfilt spot/com.hoa --equivalent-to=nsbc/com.hoa --output=results/re" + str(k)

        execCmd(cmdLtl2tgba)
        execCmd(cmdSpot)
        execCmd(cmdPldi)
        execCmd(cmdNsbc)
        execCmd(cmdAutfiltCom)
        execCmd(cmdAutfiltEquiv)
        k = k+1
    # result = execCmd(cmd)
    # pat1 = "Physical Address[\. ]+: ([\w-]+)"
    # pat2 = "IP Address[\. ]+: ([\.\d]+)"
    # MAC = re.findall(pat1, result)[0]       # 找到MAC
    # IP = re.findall(pat2, result)[0]        # 找到IP
    # print("MAC=%s, IP=%s" %(MAC, IP))


import torch
from PIL import Image
from torchvision import transforms
import torchvision
from tqdm import tqdm
import argparse
from efficientnet_pytorch import EfficientNet
from onnxsim import simplify
import onnx
import rexnetv1
import osnet
from thop import profile, clever_format
import numpy as np

def argparser():
    parser = argparse.ArgumentParser(description='Measure Accuracy in ImageNet Val')
    parser.add_argument('--model', default='resnet18', choices=['resnet18','resnet34','resnet50','resnet101', 'resnet152','efficientnet_b0','efficientnet_b1','efficientnet_b2','efficientnet_b3','efficientnet_b4','rexnetv1_1.0','rexnetv1_1.3','rexnetv1_1.5','rexnetv1_2.0','mobilenetv2','mobilenetv3-s','mobilenetv3-l', 'osnet_1.0','osnet_0.75','osnet_0.5', 'osnet_0.25'],
                        help='Detector model name')
    parser.add_argument('--export', default=False,
                        action='store_true',
                        help='dump network to onnx format')
    parser.add_argument('--data_path', default='/home/ysjo/dataset/dataset/imagenet/val/', type=str,
                        help='imagenet val dataset path')
    parser.add_argument('--batch_size', default=64, type=int,
                        help='Batch size for training')
    parser.add_argument('--num_workers', default=16, type=int,
                        help='Number of workers used in dataloading')
    args = parser.parse_args()

    return args

def accuracy(outputs, targets):
    """Compute top-5 top-1"""
    _, pred = outputs.topk(5, dim=1, largest=True, sorted=True)
    y_ = targets.unsqueeze(1).expand_as(pred)
    correct = (pred == y_).squeeze()
    correct = correct.detach().cpu()
    correct_1 = torch.sum(correct[:,:1]).item()
    correct_5 = torch.sum(correct[:,:5]).item()

    return correct_1, correct_5

if __name__ == "__main__":
    args = argparser()

    # select model
    # resnet
    if args.model == 'resnet18':
        model = torch.hub.load('pytorch/vision:v0.10.0', 'resnet18', pretrained=True)
        input_sizes = (224,224)
    elif args.model == 'resnet34':
        model = torch.hub.load('pytorch/vision:v0.10.0', 'resnet34', pretrained=True)
        input_sizes = (224,224)
    elif args.model == 'resnet50':
        model = torch.hub.load('pytorch/vision:v0.10.0', 'resnet50', pretrained=True)
        input_sizes = (224,224)
    elif args.model == 'resnet101':
        model = torch.hub.load('pytorch/vision:v0.10.0', 'resnet101', pretrained=True)
        input_sizes = (224,224)
    elif args.model == 'resnet152':
        model = torch.hub.load('pytorch/vision:v0.10.0', 'resnet152', pretrained=True)
        input_sizes = (224,224)
    # efficientnet
    elif args.model == 'efficientnet_b0':
        model = EfficientNet.from_pretrained('efficientnet-b0')
        model.set_swish(memory_efficient=False)
        image_size = EfficientNet.get_image_size('efficientnet-b0') # 224
        input_sizes = (image_size,image_size)
    elif args.model == 'efficientnet_b1':
        model = EfficientNet.from_pretrained('efficientnet-b1')
        model.set_swish(memory_efficient=False)
        image_size = EfficientNet.get_image_size('efficientnet-b1') # 224
        input_sizes = (image_size,image_size)
    elif args.model == 'efficientnet_b2':
        model = EfficientNet.from_pretrained('efficientnet-b2')
        model.set_swish(memory_efficient=False)
        image_size = EfficientNet.get_image_size('efficientnet-b2') # 224
        input_sizes = (image_size,image_size)
    elif args.model == 'efficientnet_b3':
        model = EfficientNet.from_pretrained('efficientnet-b3')
        model.set_swish(memory_efficient=False)
        image_size = EfficientNet.get_image_size('efficientnet-b3') # 224
        input_sizes = (image_size,image_size)
    elif args.model == 'efficientnet_b4':
        model = EfficientNet.from_pretrained('efficientnet-b4')
        model.set_swish(memory_efficient=False)
        image_size = EfficientNet.get_image_size('efficientnet-b4') # 224
        input_sizes = (image_size,image_size)
    # rexnet
    elif args.model == 'rexnetv1_1.0':
        model = rexnetv1.ReXNetV1(width_mult=1.0)
        model.load_state_dict(torch.load('./rexnetv1_1.0.pth'))
        input_sizes = (224,224)
    elif args.model == 'rexnetv1_1.3':
        model = rexnetv1.ReXNetV1(width_mult=1.3)
        model.load_state_dict(torch.load('./rexnetv1_1.3.pth'))
        input_sizes = (224,224)
    elif args.model == 'rexnetv1_1.5':
        model = rexnetv1.ReXNetV1(width_mult=1.5)
        model.load_state_dict(torch.load('./rexnetv1_1.5.pth'))
        input_sizes = (224,224)
    elif args.model == 'rexnetv1_2.0':
        model = rexnetv1.ReXNetV1(width_mult=2.0)
        model.load_state_dict(torch.load('./rexnetv1_2.0.pth'))
        input_sizes = (224,224)
    # mobilenet
    elif args.model == 'mobilenetv2':
        model = torch.hub.load('pytorch/vision:v0.10.0', 'mobilenet_v2', pretrained=True)
        input_sizes = (224,224)
    elif args.model == 'mobilenetv3-s':
        model = torchvision.models.mobilenet_v3_small(weights='DEFAULT')
        input_sizes = (224,224)
    elif args.model == 'mobilenetv3-l':
        model = torchvision.models.mobilenet_v3_large(weights='DEFAULT')
        input_sizes = (224,224)
    # osnet
    elif args.model == 'osnet_1.0':
        model = osnet.osnet_x1_0()
        input_sizes = (224, 224)
    elif args.model == 'osnet_0.75':
        model = osnet.osnet_x0_75()
        input_sizes = (224, 224)
    elif args.model == 'osnet_0.5':
        model = osnet.osnet_x0_5()
        input_sizes = (224, 224)
    elif args.model == 'osnet_0.25':
        model = osnet.osnet_x0_25()
        input_sizes = (224, 224)
    else:
        raise ValueError("no model")
    input = torch.randn(1, 3, input_sizes[0],  input_sizes[1])
    macs, params = profile(model, inputs=(input, ))
    macs, params = clever_format([macs, params], "%.3f")
    model.eval()
    print(f" INPUT SIZE : {input_sizes} ")

    # export model
    if args.export:
        dummy_input = torch.randn(1, 3, input_sizes[0], input_sizes[1])
        torch.onnx.export(model, dummy_input, args.model+".onnx", verbose=False, input_names=['images'], output_names=['output'])
        onnx.checker.check_model(args.model+".onnx")
        model_onnx, check = simplify(args.model+".onnx")
        onnx.save(model_onnx, args.model+".onnx")

    if args.model[:12] == 'efficientnet':
        preprocess = transforms.Compose([
            transforms.Resize(input_sizes[0]+32),
            transforms.CenterCrop(input_sizes),
            transforms.ToTensor(),
            transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
        ])
    else:
        preprocess = transforms.Compose([
            transforms.Resize(256),
            transforms.CenterCrop(input_sizes),
            transforms.ToTensor(),
            transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
        ])

    testset=torchvision.datasets.ImageFolder(root=args.data_path, transform=preprocess)
    testloader=torch.utils.data.DataLoader(testset, batch_size=args.batch_size, shuffle=False, num_workers=args.num_workers, pin_memory=True, drop_last=False)

    # move the input and model to GPU for speed if available
    if torch.cuda.is_available():
        model = model.to('cuda')

    top_1 = 0
    top_5 = 0
    p_bar = tqdm(testloader)
    with torch.no_grad():
        for data in p_bar:
            imgs, labels = data
            if torch.cuda.is_available():
                imgs = imgs.to('cuda')
                labels = labels.to('cuda')
            outputs = model(imgs)
            probabilities = torch.exp(outputs)
            ret1, ret2 = accuracy(probabilities, labels)
            top_1 += ret1
            top_5 += ret2

    # for measure inference time average 100 repetitions
    repetitions = 100
    timings = np.zeros((repetitions,1))
    starter, ender = torch.cuda.Event(enable_timing=True), torch.cuda.Event(enable_timing=True)
    img = imgs[0].unsqueeze(0)   # 1 image
    with torch.no_grad():
        for rep in range(repetitions):
            starter.record()
            _ = model(imgs)
            ender.record()
            # WAIT FOR GPU SYNC
            torch.cuda.synchronize()
            curr_time = starter.elapsed_time(ender)
            timings[rep] = curr_time
    print("!! Sumary !!")
    print(f"MACs : {macs}")
    print(f"params : {params}")
    print(f"FLOPS : {float(macs[:-1]) *2 }{macs[-1]}")
    print("!! average Inference Time !!")
    print(f"Inference time : {np.mean(timings)}ms")
    print("!! Accuracy !!")
    print(f"top-1 : {round(top_1/500, 2)}")
    print(f"top-5 : {round(top_5/500, 2)}")
    print(f"top-1-error : {round(100 - top_1/500,2)}")
    print(f"top-5-error : {round(100 - top_5/500,2)}")
    print("!! DONE !!")


from django.urls import path

from .views import PlanCreateAPIView, PlanListAPIView, PlanRetrieveUpdateDestroyAPIView

urlpatterns = [
    #  subscriptions plan urls
    path("", PlanListAPIView.as_view(), name="list_subscriptions"),
    path("<str:id>/", PlanRetrieveUpdateDestroyAPIView.as_view(), name="create_retrieve_destroy"),
    path("plan/create/", PlanCreateAPIView.as_view(), name="create_subscription"),

]


import random, os
from threading import Thread

cores = os.cpu_count()
if not cores:
    cores = 4

solutions = []
pancakes_global = []
og_size = 0
solved = []
allstacks = []
pwuezahlen = [0,0,1,2,2,3,3,4,5,5]      #erstellt mit der Tabelle aus der Aufgabenstellung und den Ergebnissen von b)
fertige = []
pwue_allelösungen = []

def genstacks(len,liste, dep=0):
    for i in range(1,len+1):
        inlist = False
        for e in range(0,dep):
            if liste[e] == i:
                inlist = True
        if not inlist:
            liste[dep]=i
            if dep < len-1:
                genstacks(len,liste.copy(),dep+1)
            else:
                allstacks.append(liste)

def get_pwue(n):
    global pancakes_global, solved, solutions, og_size
    rangee = 1
    og_size = n
    solvede = []
    pwue_last= n
    for i in range(1,n+1):
        rangee *= i
        solvede.append([])
    liste = solvede.copy()
    print("generating stacks...")
    genstacks(n,liste)
    if pwuezahlen[n-1]:
        pwue_last = pwuezahlen[n-1]
    print("calculating solutions...")
    for stacke in allstacks:
        sol = []
        pancakes_global = stacke.copy()
        for currentbest in solved:
            currentbest.clear()
        solutions.clear()

        solved = solvede.copy()
        sol.append(pancakes_global.copy())
        execute_threads(get_threads())
        sol.append(get_longest()[0])
        sol.append(get_longest()[1])

        if len(get_longest()[1])>pwue_last:
            print(f"Jeder Stapel der Länge {n} lässt sich in höchstens {len(get_longest()[1])} Pfannkuchen-Wende-Und-Ess-Operationen sortieren.")
            print(f"Stapel: {pancakes_global} Stapel sortiert: {get_longest()[0]} Lösungsweg: {get_longest()[1]}")
            return 0

        pwue_allelösungen.append(sol)
        leerzeichen = "   " * (5-len(get_longest()[0]))
        fertige.append(f"stack: {pancakes_global} stack solved: {get_longest()[0]}{leerzeichen} solution: {get_longest()[1]}")

    max_moves = 0
    currentbest = 0
    print("finding longest solution...")
    for solution in pwue_allelösungen:
        if len(solution[2]) > max_moves:
            max_moves = len(solution[2])
            currentbest = solution

    with open(f"daten{n}.txt","w",encoding="utf8") as output:
        for line in fertige:
            output.write(line)
            output.write("\n")
        output.write(f"Jeder Stapel der Länge {len(currentbest[0])} lässt sich in höchstens {len(currentbest[2])} Pfannkuchen-Wende-Und-Ess-Operationen sortieren.")
    print(f"Jeder Stapel der Länge {len(currentbest[0])} lässt sich in höchstens {len(currentbest[2])} Pfannkuchen-Wende-Und-Ess-Operationen sortieren.")
    print(f"Stapel: {currentbest[0]} Stapel sortiert: {currentbest[1]} Lösungsweg: {currentbest[2]}")

def sort(pancakes,base = 0,lösungsweg=[]):
    global solutions
    newpancakes = []
    for i in range(len(pancakes)-base-2,-1,-1):
        newpancakes.append(pancakes[i])

    for i in range(len(pancakes)-base,len(pancakes)):
        newpancakes.append(pancakes[i])
    if sorted(newpancakes)and len(newpancakes)>1:
        solved[len(pancakes)-1].append((pancakes))
        solutions.append([newpancakes,lösungsweg])
    return(newpancakes)

def sorted(pancakes):
    previous = int(pancakes[-1])
    for i in range(len(pancakes)-1,-1,-1):
        current = int(pancakes[i])
        if current > previous:
            return False
        previous = current
    return True

def sort_stack(stack,lösungsweg):
    if not solved[len(stack)]:
        for i in range(0, len(stack)):
            if not solved[len(stack)]:
                lösungsweg_copy = lösungsweg.copy()
                lösungsweg_copy.append(i)
                nstack = stack.copy()
                nstack = sort(nstack,i,lösungsweg_copy)
                if len(nstack)>1:
                    sort_stack(nstack,lösungsweg_copy)

def start_sort(startdata):
    for start in startdata:
        pancakes = pancakes_global.copy()
        pancakes = sort(pancakes,start,[start])
        sort_stack(pancakes,[start])

def get_longest():
    longest = solutions[0][0]
    solution = solutions[0][1]
    for stack in solutions:
        if len(stack[0]) > len(longest):
            longest = stack[0]
            solution = stack[1]
    return(longest, solution)

def get_threads():
    if sorted(pancakes_global):
        solved[len(pancakes_global)-1].append((pancakes_global))
        solutions.append([pancakes_global,[None]])
    threads = []
    for i in range(0,og_size):
        if i >= cores:
            threads[i%cores].append(i)
        else:
            threads.append([i])
    return threads

def execute_threads(threadlist):
    exe_threads = []
    for data in threadlist:
        exe_threads.append(Thread(target=start_sort, args=(data,)))
    for e in exe_threads:
        e.start()
    for e in exe_threads:
        e.join()

print("Stapelgröße angeben")
stapelgröße = input()
get_pwue(int(stapelgröße))
input()


# -*- coding: utf-8 -*-
# Author : zenk
# 2013-07-05 20:32
from os import path
from collections import defaultdict
import re

from PyQt4.QtGui import QDialog
from PyQt4.QtGui import QFileDialog
from PyQt4.QtGui import QGridLayout
from PyQt4.QtGui import QLineEdit
from PyQt4.QtGui import QLabel
from PyQt4.QtGui import QIntValidator
from PyQt4.QtGui import QMessageBox
from PyQt4.QtGui import QPushButton
from PyQt4.QtGui import QVBoxLayout

from PyQt4.QtCore import SIGNAL

import xlrd

class ReplaceI18NDialog(QDialog):
  def __init__(self, config_name, parent=None):
    super(ReplaceI18NDialog, self).__init__(parent)
    self.parent = parent
    grid_layout = QGridLayout()
    grid_layout.addWidget(QLabel(u'表单名字/序号'), 0, 0)
    self.sheet_index_input = QLineEdit(config_name, self)
    grid_layout.addWidget(self.sheet_index_input, 0, 1)

    grid_layout.addWidget(QLabel(u'列'), 1, 0)
    self.column_input = QLineEdit("1", self)
    int_validator = QIntValidator()
    int_validator.setRange(1, 100)
    self.column_input.setValidator(int_validator)
    grid_layout.addWidget(self.column_input, 1, 1)

    grid_layout.addWidget(QLabel(u'文件'), 2, 0)
    self.file_input = QLineEdit("", self)
    grid_layout.addWidget(self.file_input, 2, 1)
    select_file_btn = QPushButton(u'选择')
    grid_layout.addWidget(select_file_btn, 2, 2)

    do_btn = QPushButton(u'替换')
    main_layout = QVBoxLayout()
    main_layout.addLayout(grid_layout)
    main_layout.addWidget(do_btn)
    self.setLayout(main_layout)

    self.connect(select_file_btn, SIGNAL("clicked()"), self.select_file)
    self.connect(do_btn, SIGNAL("clicked()"), self.replace)

  def select_file(self):
    filename = unicode(QFileDialog.getOpenFileName(self, "Open File",
                                           "", "Excel (*.xls)"))
    if not path.exists(filename):
      QMessageBox.information(self, u"i18n替换",
          u'文件:%s不存在' % filename)
      return
    book = xlrd.open_workbook(filename)
    sheet_name = unicode(self.sheet_index_input.text())
    sheet = None
    if sheet_name in book.sheet_names():
      sheet = book.sheet_by_name(sheet_name)
    elif re.match("\d+", sheet_name):
      sheet = book.sheet_by_index(int(sheet_name) - 1)
    if not sheet:
      QMessageBox.information(self, u'i18n替换',
          u'表单名字/索引:%s不存在' % sheet_name)
      return
    self.text_dic = defaultdict(str)
    for k, v in zip(sheet.col_values(0),
        sheet.col_values(int(unicode(self.column_input.text())))):
        self.text_dic[k] = v
    self.file_input.setText(filename)

  def replace(self):
    not_replaced = self.parent.replace_i18n(self.text_dic)
    QMessageBox.information(self, u'i18n替换',
        u'替换成功%s' % ('' if not not_replaced else u'\n以下字符串没有被替换:%s' % not_replaced))
    self.close()


"""Charge subscriptions' spending to a cost centre."""
from datetime import date, timedelta
from typing import Any, Dict, List, Optional
from uuid import UUID

import sqlalchemy
from fastapi import Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy import and_, between, desc, func, insert, select

from rctab.constants import ADMIN_OID
from rctab.crud.accounting_models import (
    cost_recovery,
    cost_recovery_log,
    finance,
    usage,
)
from rctab.crud.auth import token_admin_verified
from rctab.crud.models import database
from rctab.crud.schema import CostRecovery, UserRBAC
from rctab.routers.accounting.routes import router
from rctab.routers.accounting.usage import authenticate_usage_app

class CostRecoveryMonth(BaseModel):
    """A month to do cost-recovery for."""

    # The first day of the month
    first_day: date

def validate_month(
    month_to_recover: CostRecoveryMonth,
    last_recovered_month: Optional[CostRecoveryMonth],
) -> None:
    """Raise if month shouldn't be recovered."""
    if last_recovered_month:
        # If we have previously recovered a month,
        # we know exactly which month we should be recovering
        month_expected = last_recovered_month.first_day + timedelta(days=31)
        month_expected = date(
            year=month_expected.year, month=month_expected.month, day=1
        )
        if month_to_recover.first_day != month_expected:
            raise HTTPException(
                status_code=400, detail="Expected " + month_expected.isoformat()[:-3]
            )

    # We can never recover later than last month
    middle_of_this_month = date.today().replace(day=15)
    middle_of_last_month = middle_of_this_month - timedelta(days=30)
    first_of_last_month = middle_of_last_month.replace(day=1)
    if month_to_recover.first_day > first_of_last_month:
        raise HTTPException(
            status_code=400,
            detail="Cannot recover later than " + first_of_last_month.isoformat()[:-3],
        )

async def calc_cost_recovery(
    recovery_month: CostRecoveryMonth, commit_transaction: bool, admin: UUID
) -> List[CostRecovery]:
    """Calculates the cost recovery for a given period.

    Cost recovery must have been calculated for all previous months
    but not for this month.
    """
    last_recovered_day = await database.fetch_one(
        select([cost_recovery_log]).order_by(desc(cost_recovery_log.c.month))
    )
    last_recovered_month = (
        CostRecoveryMonth(first_day=last_recovered_day["month"])
        if last_recovered_day
        else None
    )
    if commit_transaction:
        validate_month(recovery_month, last_recovered_month)

    transaction = await database.transaction()
    try:

        cost_recovery_ids = []

        # We're only interested in subscriptions if they have a finance record
        subscription_ids = [
            r["sub_id"]
            for r in await database.fetch_all(
                select(
                    [func.distinct(finance.c.subscription_id).label("sub_id")]
                ).where(
                    between(
                        recovery_month.first_day, finance.c.date_from, finance.c.date_to
                    )
                )
            )
        ]

        for subscription_id in subscription_ids:

            usage_row = await database.fetch_one(
                select([func.sum(usage.c.total_cost).label("the_sum")])
                .where(
                    func.date_trunc(
                        "month", sqlalchemy.cast(usage.c.date, sqlalchemy.Date)
                    )
                    == func.date_trunc(
                        "month",
                        sqlalchemy.cast(recovery_month.first_day, sqlalchemy.Date),
                    )
                )
                .where(usage.c.subscription_id == subscription_id)
            )
            # This should always return a row, though the_sum can be NULL
            assert usage_row
            total_usage = usage_row["the_sum"] or 0.0
            usage_recharged = 0

            # The lower the value of priority, the higher importance
            finance_periods = await database.fetch_all(
                select([finance])
                .where(
                    and_(
                        between(
                            recovery_month.first_day,
                            finance.c.date_from,
                            finance.c.date_to,
                        ),
                        finance.c.subscription_id == subscription_id,
                    )
                )
                .order_by(finance.c.priority)
            )

            # We divide the usage between the eligible finance periods
            for finance_period in finance_periods:

                cost_recovery_row = await database.fetch_one(
                    select([func.sum(cost_recovery.c.amount).label("the_sum")]).where(
                        cost_recovery.c.finance_id == finance_period["id"]
                    )
                )

                # This should always return a row, though the_sum can be NULL
                assert cost_recovery_row
                recovered_amount = cost_recovery_row["the_sum"] or 0.0

                recoverable_amount = min(
                    # The smallest of
                    # a) the amount remaining on the finance ID and
                    # b) the amount of usage yet to be charged
                    finance_period["amount"] - recovered_amount,
                    total_usage - usage_recharged,
                )

                # Keep track of how much of this subscription's usage
                # has been recharged
                usage_recharged += recoverable_amount

                cost_recovery_id = await database.execute(
                    insert(
                        cost_recovery,
                        {
                            "subscription_id": finance_period["subscription_id"],
                            "month": recovery_month.first_day,
                            "finance_code": finance_period["finance_code"],
                            "amount": recoverable_amount,
                            "date_recovered": None,
                            "finance_id": finance_period["id"],
                            "admin": admin,
                        },
                    )
                )
                cost_recovery_ids.append(cost_recovery_id)

        inserted_rows = await database.fetch_all(
            select([cost_recovery]).where(cost_recovery.c.id.in_(cost_recovery_ids))
        )

        # Note that we patch CostRecovery as a unit testing hack
        cost_recoveries = [CostRecovery(**dict(cr)) for cr in inserted_rows]

        if commit_transaction:
            await database.execute(
                insert(
                    cost_recovery_log,
                    {"month": recovery_month.first_day, "admin": admin},
                )
            )
            await transaction.commit()
        else:
            await transaction.rollback()

        return cost_recoveries

    except BaseException:
        await transaction.rollback()
        raise

@router.post("/app-cost-recovery", status_code=200)
async def calc_cost_recovery_app(
    recovery_period: CostRecoveryMonth,
    _: Dict[str, str] = Depends(authenticate_usage_app),
) -> Any:
    """Route for the usage app to trigger cost recovery calculation."""
    await calc_cost_recovery(
        recovery_period, commit_transaction=True, admin=UUID(ADMIN_OID)
    )

    return {"status": "success", "detail": "cost recovery calculated"}

@router.post("/cli-cost-recovery", response_model=List[CostRecovery])
async def post_calc_cost_recovery_cli(
    recovery_month: CostRecoveryMonth, user: UserRBAC = Depends(token_admin_verified)
) -> Any:
    """Route for the CLI to trigger cost recovery calculation."""
    resp = await calc_cost_recovery(
        recovery_month, commit_transaction=True, admin=user.oid
    )

    return resp

@router.get("/cli-cost-recovery", response_model=List[CostRecovery])
async def get_calc_cost_recovery_cli(
    recovery_month: CostRecoveryMonth, user: UserRBAC = Depends(token_admin_verified)
) -> Any:
    """Route for the CLI to do a dry-run of the cost recovery calculation."""
    result = await calc_cost_recovery(
        recovery_month, commit_transaction=False, admin=user.oid
    )
    return result


# Clear any data that has been downloaded

import os
import shutil

# Delete all files and directories in a path
def obliviate(path):
    for fname in os.listdir(path):
        print(f'deleting{fname} under {path}')
        file_path = os.path.join(path, fname)
        try:
            # Delete file in path
            if os.path.isfile(file_path):
                os.remove(file_path)

            # Delete directory in path
            elif os.path.isdir(file_path):
                shutil.rmtree(file_path)
        except Exception as e:
            # Failsafe: potential error for deleting paths
            print(f'Failed to delete {file_path}. Reason: {e}')

# Delete files for all paths
def clean(paths):
    for path in paths:
        obliviate(path)


'''Integration test: complex Heartbeat definition

'''
import pytest

from fjarrsyn.core.agent import Agent
from fjarrsyn.core.instructor import Interpreter
from fjarrsyn.core.message import Belief, Resource
from fjarrsyn.core.scaffold_map import ResourceMap
from fjarrsyn.core.policy import AutoResourceCondition, Heartbeat

REF_B1 = [1,2,3,3]
REF_I1 = [False, False, False, True]
REF_B2 = [4,5,6,6,6]
REF_I2 = [False, False, False, True, True]

def test_main():
    belief = Belief('dummy', ('a1',))
    resource = Resource('internal energy', ('level',))
    mapper = ResourceMap('eat energy', 'delta', 'level', ('shift',))
    interpreter1 = Interpreter('thinker', lambda x: (x + 1, -1), belief, belief,
                               resource_map_output=mapper)
    interpreter2 = Interpreter('thinker X', lambda x: (x + 1, -3), belief, belief,
                               resource_map_output=mapper)
    battery = AutoResourceCondition('battery left', lambda x: x>0)
    heart_1 = Heartbeat('big heart', battery, ticker_arithmetic=lambda : 2, max_ticker=4)
    heart_2 = Heartbeat('small heart', battery, ticker_arithmetic=lambda : 1, max_ticker=4)

    agent_1 = Agent('A1')
    agent_1.set_organs(interpreter1, interpreter2)
    belief.set_values([1])
    resource.set_values([10])
    agent_1.set_message(belief)
    agent_1.set_scaffold(resource)
    agent_1.set_policies(heart_1, heart_2)

    assert (agent_1.belief['dummy'].values()[0] == REF_B1[0])
    assert (agent_1.inert == REF_I1[0])
    agent_1.pump('big heart')
    agent_1.interpret('thinker')
    assert (agent_1.belief['dummy'].values()[0] == REF_B1[1])
    assert (agent_1.inert == REF_I1[1])
    agent_1.pump('big heart')
    agent_1.interpret('thinker')
    assert (agent_1.belief['dummy'].values()[0] == REF_B1[2])
    assert (agent_1.inert == REF_I1[2])
    agent_1.pump('big heart')
    agent_1.interpret('thinker')
    assert (agent_1.belief['dummy'].values()[0] == REF_B1[3])
    assert (agent_1.inert == REF_I1[3])

    agent_1.revive()
    assert (agent_1.inert == False)

    agent_1.pump('small heart')
    agent_1.interpret('thinker X')
    assert (agent_1.belief['dummy'].values()[0] == REF_B2[0])
    assert (agent_1.inert == REF_I2[0])
    agent_1.pump('small heart')
    agent_1.interpret('thinker X')
    assert (agent_1.belief['dummy'].values()[0] == REF_B2[1])
    assert (agent_1.inert == REF_I2[1])
    agent_1.pump('small heart')
    agent_1.interpret('thinker X')
    assert (agent_1.belief['dummy'].values()[0] == REF_B2[2])
    assert (agent_1.inert == REF_I2[2])
    agent_1.pump('small heart')
    agent_1.interpret('thinker X')
    assert (agent_1.belief['dummy'].values()[0] == REF_B2[3])
    assert (agent_1.inert == REF_I2[3])
    agent_1.pump('small heart')
    agent_1.interpret('thinker X')
    assert (agent_1.belief['dummy'].values()[0] == REF_B2[4])
    assert (agent_1.inert == REF_I2[4])


class Solution(object):
    def setZeroes(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: void Do not return anything, modify matrix in-place instead.
        """
        nrows = len(matrix)  # m
        ncols = len(matrix[0])  # n
        zero_cols = set()
        zero_rows = set()

        # O(m*n)
        for r in range(nrows):
            for c in range(ncols):
                if matrix[r][c] == 0:
                    zero_cols.add(c)
                    zero_rows.add(r)

        for r in zero_rows:
            for c in range(ncols):
                matrix[r][c] = 0

        for c in zero_cols:
            for r in range(nrows):
                matrix[r][c] = 0


# inputs 文件夹和 testplans 中获得输入，生成 json 格式的测试用例

import json
from subprocess import run, PIPE
from os import path

join = path.join

def execf(params):
    p=run(['./source/a.out']+params, stdout=PIPE)
    return(p.stdout)

with open('./testplans.alt/universe') as fr:
    plans = fr.readlines()

res=[]

for item in plans:
    print('running {}'.format(item))

    params = item.strip().split()

    res.append({
        'params': params,
        'output': execf(params).decode('ascii'),
    })

with open('cases.json','w') as fr:
    json.dump(res, fr, indent=2)


import unittest
import tempfile
import os
import sys
import pathlib
import contextlib

HERE = pathlib.Path(__file__).absolute().parent
# print(HERE.parent)
sys.path.insert(0, str(HERE.parent))

IMGUI_H = HERE.parent / 'libs/imgui/imgui.h'

from pycpptool.get_tu import get_tu
from clang import cindex

@contextlib.contextmanager
def tmp(src):
    fd, tmp_name = tempfile.mkstemp(prefix='tmpheader_', suffix='.h')
    os.close(fd)
    with open(tmp_name, 'w', encoding='utf-8') as f:
        f.write(src)
    try:
        yield pathlib.Path(tmp_name)
    finally:
        os.unlink(tmp_name)

class StructDecl:
    def __init__(self, name, *fields):
        self.name = name
        self.fields = fields

    def __eq__(self, rhs) -> bool:
        return (self.name == rhs.name and len(self.fields) == len(rhs.fields))

    def __repr__(self) -> str:
        return f'struct {self.name}{{}}'

    @classmethod
    def parse(cls, c: cindex.Cursor) -> 'StructDecl':
        fields = []
        for child in c.get_children():
            fields.append(child)
        # if len(fields) == 0. forward decl
        return StructDecl(c.spelling, *fields)

class TypedefDecl:
    def __init__(self, name: str, src: str):
        self.name = name
        self.src = src

    def __repr__(self) -> str:
        return f'typedef {self.name} = {self.src}'

    @classmethod
    def parse(cls, c: cindex.Cursor) -> 'TypedefDecl':
        children = [child for child in c.get_children()]
        assert (len(children) == 0)
        # tokens = [token.spelling for token in c.get_tokens()]
        return TypedefDecl(c.spelling, c.underlying_typedef_type)

EXPECTS = {
    'ImDrawChannel': StructDecl('ImDrawChannel'),
    'ImDrawCmd': StructDecl('ImDrawCmd'),
    'ImDrawData': StructDecl('ImDrawData'),
    'ImDrawList': StructDecl('ImDrawList'),
    'ImDrawListSharedData': StructDecl('ImDrawListSharedData'),
    'ImDrawListSplitter': StructDecl('ImDrawListSplitter'),
    'ImDrawVert': StructDecl('ImDrawVert'),
    'ImFont': StructDecl('ImFont'),
    'ImFontAtlas': StructDecl('ImFontAtlas'),
    'ImFontConfig': StructDecl('ImFontConfig'),
    'ImFontGlyph': StructDecl('ImFontGlyph'),
    'ImFontGlyphRangesBuilder': StructDecl('ImFontGlyphRangesBuilder'),
    'ImColor': StructDecl('ImColor'),
    'ImGuiContext': StructDecl('ImGuiContext'),
    'ImGuiIO': StructDecl('ImGuiIO'),
    'ImGuiInputTextCallbackData': StructDecl('ImGuiInputTextCallbackData'),
    'ImGuiListClipper': StructDecl('ImGuiListClipper'),
    'ImGuiOnceUponAFrame': StructDecl('ImGuiOnceUponAFrame'),
    'ImGuiPayload': StructDecl('ImGuiPayload'),
    'ImGuiSizeCallbackData': StructDecl('ImGuiSizeCallbackData'),
    'ImGuiStorage': StructDecl('ImGuiStorage'),
    'ImGuiStyle': StructDecl('ImGuiStyle'),
    'ImGuiTextBuffer': StructDecl('ImGuiTextBuffer'),
    'ImGuiTextFilter': StructDecl('ImGuiTextFilter'),
}

def parse(c: cindex.Cursor):
    if c.kind == cindex.CursorKind.UNEXPOSED_DECL:
        tokens = [t.spelling for t in c.get_tokens()]
    elif c.kind == cindex.CursorKind.STRUCT_DECL:
        return StructDecl.parse(c)
    elif c.kind == cindex.CursorKind.TYPEDEF_DECL:
        return TypedefDecl.parse(c)
    else:
        print(c.kind)

class ImGuiTest(unittest.TestCase):
    def test_int(self) -> None:
        tu = get_tu(IMGUI_H)
        self.assertIsInstance(tu, cindex.TranslationUnit)

        # TRANSLATION_UNIT
        c: cindex.Cursor = tu.cursor
        self.assertIsInstance(c, cindex.Cursor)
        self.assertEqual(cindex.CursorKind.TRANSLATION_UNIT, c.kind)
        self.assertIsNone(c.location.file)

        count = 0
        for i, c in enumerate(c.get_children()):
            if c.location.file.name != str(IMGUI_H):
                continue
            count += 1
            with self.subTest(i=i, spelling=c.spelling):
                self.assertEqual(EXPECTS.get(c.spelling), parse(c))
            if count > len(EXPECTS):
                break

if __name__ == '__main__':
    unittest.main()


from numpy import linalg as la
from .utils import rec_from_factors

def PoF(X, factors, mask=None):
    """
    The percentage of fitness (POF) metric
    INPUT:
        - <tensor> X: the original tensor
        - <tensor> rec: the reconstructed tensor
    OUTPUT:
        - <scalar> PoF_metric: the metric, higher is better
    """
    if mask is None:
        Rec = rec_from_factors(factors)
        PoF_metric = 1 - la.norm(Rec - X) / la.norm(X)
    else:
        Rec = rec_from_factors(factors)
        PoF_metric = 1 - la.norm(mask * Rec - X) / la.norm(X)
    return PoF_metric


from DNNCTF import DNNCTF
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

DATASET = 'iris.data'
MODEL = 'model'

df = pd.read_csv(DATASET, header=None)

data = df.iloc[:, :-1]
target = df.iloc[:,-1]

x_train, x_test, y_train, y_test = train_test_split(data, target, test_size=0.2, random_state=0)
print('Dataset created.')

classifier = DNNCTF(
    path=MODEL,
    layers =[10, 10, 10],
    learning_rate=0.001,
    steps=1000,
    batch_size=10,
    log=True
    )
print('Classifier instantiated.')

classifier.fit(x_train, y_train)
print('Classifier trained.')

classifier = DNNCTF(path=MODEL, log=False)
print('Classifier restored.')

y_pred = classifier.predict(x_test)
print('Classifier tested')

accuracy = accuracy_score(y_test, y_pred)
print(accuracy)


import numpy as np
from function import gradient_descent, get_data, plot_model, plot_cost

# Press the green button in the gutter to run the script.
def main():
    # perform gradient descent with arbitrary number of features
    # also prints the cost for the first and last iterations for comparison

    """## Part 1: linear regression with one variable: food truck

gradient_descent function at the top of the notebook. Parameters printed below.

Cost function and model with data plotted below.
    """

    X, Y = get_data('Data/food_truck_data.txt', ',')  # standard deviation and average are not needed in part1
    # for the problem.The data consists of two columns; the first column is the population of a city and the second column is the profit of a food truck in that city.A negative value for profit indicates a loss.

    # the model is h(theta)=theta[0] *x0 + theta[1]*x1 = theta.T*X
    initial_theta = np.array([0, 0])  # initial value for theta
    alpha = 0.002  # learning rate hyperparameter
    iterations = 10000  # number of iterations
    theta, cost = gradient_descent(X, Y, initial_theta, alpha, iterations)
    print(initial_theta)
    plot_cost(cost)
    plot_model(X[:, 1], Y, theta)
    print('example prediction: \npopulation(in 10,000s): 17.5 \nProfit(in $10,000): ', theta[0] + theta[1] * 17.5)

    """## Part 2: Linear regression with multiple variables: housing price

Features scaled in get_data function. Input is scaled and output is not.

gradient_descent function at the top of the notebook. Parameters printed below.

Cost function plotted below.

Sample prediction below.

    """

    # features (but not output) scaled in get_data
    X, Y, std_X, avg_X = get_data('Data/housing_price_data.txt', ',')

    # the model is h(theta)=theta[0] *x0 + theta[1]*x1 + theta[2]*x2 = theta.T*X
    initial_theta = np.array([0, 0, 0])  # initial value for theta
    alpha = 0.02  # learning rate hyperparameter
    iterations = 10000  # number of iterations
    theta, cost = gradient_descent(X, Y, initial_theta, alpha, iterations)

    print('theta = ', theta, '\nmodel: h(theta)= ', theta[0], ' + ', theta[1], ' * x1 + ', theta[2], '* x2',
          '\n(input scaled, output not scaled)')
    plot_cost(cost)

    """**Prediction:**
    Assume features of a house and predict a good market price: square feet, bedrooms
    """

    house = np.array([2000, 4])
    scaled_house = (house - avg_X) / std_X
    print('predicted price for house of ', house[0], 'square feet and ', house[1], 'bedrooms: $',
          theta[0] + theta[1] * scaled_house[0] + theta[2] * scaled_house[1])

if __name__ == '__main__':
    main()


def edit_distance(word_one, word_two):
    """
    Find the edit distance between two words
    """

    # short-circuit conditions
    if word_one == word_two:
        return 0

    shorter = min(word_one, word_two, key=len)
    longer = max(word_one, word_two, key=len)

    if not shorter and longer:
        return len(longer)

    edit_matrix = []

    for _ in range(len(word_one)):
        row = [0] * len(word_two)
        edit_matrix.append(row)

    for idx_one, char_one in enumerate(word_one):
        for idx_two, char_two in enumerate(word_two):
            edit = 0 if char_one == char_two else 1
            prev_edits = []
            # check above
            if idx_one > 0:
                prev_edits.append(edit_matrix[idx_one-1][idx_two])

            # check left
            if idx_two > 0:
                prev_edits.append(edit_matrix[idx_one][idx_two-1])

            # check diagonal
            if idx_one > 0 and idx_two > 0:
                prev_edits.append(edit_matrix[idx_one-1][idx_two-1])

            prev_edit_min = min(prev_edits) if prev_edits else 0
            edit_matrix[idx_one][idx_two] = prev_edit_min + edit

    return edit_matrix[-1][-1]

def make_palindrome(s):
    """
    Make a palindrome by adding a minimal number of letters
    """

    # TODO: make optimized version of algorithm
    if s == s[::-1]:
        return s

    if s[0] == s[-1]:
        return s[0] + make_palindrome(s[1:-1]) + s[0]

    first = s[0] + make_palindrome(s[1:]) + s[0]
    last = s[-1] + make_palindrome(s[:-1]) + s[-1]

    if len(first) == len(last):
        return min(first, last)

    return min(first, last, key=len)

def find_second_largest_node(root):
    """
    Find the second-largest node in a binary search tree
    """

    val = []
    count = [0]

    def _inorder(node):
        # no element, return
        if not node or count[0] == 2:
            return

        _inorder(node.right)

        count[0] += 1
        if count[0] == 2:
            val.append(node)

        _inorder(node.left)

    _inorder(root)

    return val[0] if val else None

def powerset(s):
    """
    Generate the powerset of a
    """

    new_s = [[]]
    for elt in s:
        new_s += [x + [elt] for x in new_s]

    return new_s


from abc import ABCMeta, abstractmethod
from collections import OrderedDict
from blenderneuron.activity import Activity

class RootGroup:
    __metaclass__ = ABCMeta

    def __init__(self):
        self.name = ""
        self.roots = OrderedDict()

        self.import_synapses = False
        self.interaction_granularity = 'Cell'

        self.record_activity = False
        self.recording_granularity = 'Cell'
        self.record_variable = "v"
        self.recording_period = 1.0
        self.recording_time_start = 0
        self.recording_time_end = 0

        self.activity = Activity()

    def __str__(self):
        return self.name

    def clear_activity(self):
        # Clear group level activity
        self.activity.clear()

        # Cell and section level activity
        for root in self.roots.values():
            root.clear_activity(recursive=True)

        # Segment level
        for root in self.roots.values():
            root.clear_3d_segment_activity()

    def to_dict(self,
                include_activity=False,
                include_root_children=False,
                include_coords_and_radii=False):
        """

        :param include_activity:
        :param include_root_children:
        :param include_coords_and_radii:
        :return:
        """
        result = {
            "name": self.name,
            "roots": [root.to_dict(include_activity, include_root_children, include_coords_and_radii) for root in self.roots.values()],
            "import_synapses": self.import_synapses,
            "interaction_granularity": self.interaction_granularity,
            "record_activity": self.record_activity,
            "recording_granularity": self.recording_granularity,
            "record_variable": self.record_variable,
            "recording_period": self.recording_period,
            "recording_time_start": self.recording_time_start,
            "recording_time_end": self.recording_time_end,
        }

        if include_activity:
            result.update({
                "activity": self.activity.to_dict(),
            })

        return result


import routerFunctions
import commonFunctions
import dataPktFunctions
import selectRP
import time
import threading
import sys
import struct
import json
import os
import itertools
from socket import *

if __name__ == "__main__":

    #read the router's ID from the command line input -id
    myID = int(commonFunctions.getID())
    print("My ID is : {}".format(myID))

    nodeGraph = {str(myID): []}
    #print(nodeGraph)

    #Data structure to keep track of sequence number of received
    #link state packets
    linkStateSeqNumber = {}

    #if device has no routing table, a file and template will be created
    if(routerFunctions.checkForRoutingTable(myID) == 0):
        print("Creating Initial Routing Table")
        routerFunctions.createFirstRoutingTable(myID)

    #prepare hello packet
    pkttype = 0x05
    #src = myID
    seq = 0x01
    helloACKCounter = 0
    length = len(routerFunctions.getIpFromRoute())
    #routerHelloPacket = struct.pack('BBB', pkttype, seq, src)
    routerHelloPacket = struct.pack('BBB', pkttype, seq, myID)

    ipAddresses = routerFunctions.getIpFromRoute()
    localStoreIPAddresses = ipAddresses

    """
    Router "Hello" logic. The router spins a new thread every iteration of the loop. The thread
    loops through the ipAddresses array and sends a router hello packet. If the logic succesfully
    receives an ACK, the ip address for that ACK is removed from the ipAddresses array.
    """
    while(helloACKCounter != length):
        routerHelloThread = threading.Thread(target = routerFunctions.sendRouterHello, args=(myID, routerHelloPacket, ipAddresses))
        routerHelloThread.start()
        temp, nodeGraph, ipOfACK = routerFunctions.receiveRouterHello(myID, nodeGraph)
        if(ipOfACK is not None):
            try:
                localStoreIPAddresses.remove(ipOfACK)
            except:
                print("No such IP")
        helloACKCounter = helloACKCounter + temp
        routerHelloThread.join()
        ipAddresses = localStoreIPAddresses

    #initializes Link State transmission to occur every 10 seconds
    routerFunctions.sendLinkState(myID, nodeGraph)

    while True:
        #listen on all ports logic here

        receivedPkt, addr = routerFunctions.receive_packet('0.0.0.0', 8888)
        packetType = routerFunctions.decodePktType(receivedPkt)

        #if packet type 1, Hello, respond with Hello ACK
        if(packetType == 1):
            helloType, helloSeq, helloSrc = routerFunctions.read_hello(receivedPkt)
            print("HelloSrc is: {}".format(helloSrc))

            #Call a function to DO something with the SRC you got.
            routerFunctions.sendHelloACK(helloSrc)

            #!! This should be an append situation, not a completely new file
            #This is an artifact from testing, should be replaced with an append
            routerFunctions.addHostToGraph(helloSrc, myID, nodeGraph)

        if(packetType == 2):
            ipAddresses = routerFunctions.getIpFromRoute()
            seq, length, src, data = routerFunctions.decodeLinkStatePkt(receivedPkt)
            """
            print("Here's the src value")
            print(src)
            print("Here the data")
            print(data)
            print(linkStateSeqNumber)
            """
            if(src != myID):
                if(src > 150):
                    ipAddresses = routerFunctions.getIpFromRoute()
                    ipAddresses.remove(addr[0])
                linkStateForwardThread = threading.Thread(target=routerFunctions.forwardLinkState, args=(ipAddresses, receivedPkt))
                linkStateForwardThread.run()
                nodeGraph = routerFunctions.updateGraph(seq, src, linkStateSeqNumber, data, nodeGraph)
                #Run dijkstra after updating nodeGraph
                routerFunctions.runDijkstra(nodeGraph, myID)

                #Seeing if clearing this slows things down..?
                packetType = 0

            #spin new thread to forward link state on all nodes except the node it
            #came in on!!

        #In the event a router hello packet was previously missed
        if(packetType == 5):
            helloACKpkt = struct.pack('BBB', 0x04, 0x01, myID)
            pkttype, seq, srcVal = struct.unpack('BBB', receivedPkt)
            my_socket = socket(AF_INET, SOCK_DGRAM)
            my_socket.sendto(helloACKpkt, (commonFunctions.convertID(srcVal), 8888))
            my_socket.close()
            print("Got a hello message!")

        if(packetType == 7):
            print("Recveied Data Packet")
            #print("Sending dataACK")
            #print(addr)
            time.sleep(1)
            routerFunctions.sendDataACK(addr[0])
            #decode packet
            seq, recID, ndest, rdest, dest1, dest2, dest3, data = commonFunctions.decodeDataPkt(receivedPkt)
            pktType = 0x07
            n = 3
            print("Received PKT     pktType, seq, src, ndest, selectedRP, dests[0], dests[1], dests[2], data")
            print("with information   {}       {}   {}    {}       {}           {}         {}         {}      {}".format(pktType, seq, recID, ndest, rdest, dest1, dest2, dest3, data))
            #Determine Core router runctionality or RP router functionality
            if (int(dest1) == int(dest2) == int(dest3) == 0):
                print("Received data packet from hostSender")
                #Assume Core Router functionality
                #If ndest is 1 unicast message to dest1
                #n from k out of n (hardcoded to 3 for this project)
                selectedRP, selectedDests = selectRP.selectRP(ndest,n,myID,recID)
                dests = [0] * 3
                dests[0:len(selectedDests)] = selectedDests

                if (ndest == 1):
                    print("ndest was 1, preparing to send unicast to destination")
                    #send datapkt to dest1
                    selectedRP = 0
                    datapkt = commonFunctions.createDataPacket(pktType, seq, recID, ndest, selectedRP, dests[0], dests[1], dests[2], data)
                    nextHop = commonFunctions.getNextHop(myID,dests[0])
                    print("Created PKT      pktType, seq, src, ndest, rdest, dests[0], dests[1], dests[2], data")
                    print("with information   {}       {}   {}    {}       {}     {}       {}        {}        {}".format(pktType, seq, recID, ndest, selectedRP, dests[0], dests[1], dests[2], data))
                    routerFunctions.sendData(datapkt, nextHop, myID)

                else:
                    if myID == selectedRP:
                        print("Core Router is also RP")
                        rdest = 0
                        dataPktFunctions.rpFunction(myID, pktType, n, seq, recID, ndest, rdest, dests[0], dests[1], dests[2], data)
                    else:
                        print("ndest was {}, preparing to send to RP".format(ndest))
                        dataPktFunctions.sendToRP(myID, pktType, n, seq, recID, ndest, rdest, selectedRP, dests, data)

            elif (ndest == 1 and rdest == 0):
                print("router along path to destination, preparing to forward along message")
                dataPktFunctions.forwardDataPkt(myID, dest1, receivedPkt)

            elif (rdest != 0 and myID != rdest):
                print("router along path to RP, preparing to forward along message")
                dataPktFunctions.forwardDataPkt(myID, rdest, receivedPkt)

            else:
                print("router along path to multiple destinations, checking to see how to forward message along")
                dataPktFunctions.rpFunction(myID, pktType, n, seq, recID, ndest, rdest, dest1, dest2, dest3, data)

"""
#Just some test code
destPath = [[1,2,3],[1,5,6],[1,7,8]]
destPath = [[102],[103]]
lookaheadFlag = []
index=range(len(destPath))
for a, b in itertools.combinations(index, 2):
    if destPath[a][0] == destPath[b][0]:
        lookaheadFlag.append([a,b])
print(lookaheadFlag)
"""


from django.urls import path
from .views import *

urlpatterns = [
    path('addtocart/<int:pk>/', add_to_cart, name='addtocart'),
    path('cart/', cart_view, name='cart'),
    path('remove/<int:pk>/', remove_from_cart, name='removecart'),
    path('increase/<str:pk>/', increase_cart, name='increasecart'),
    path('decrease/<str:pk>/', decrease_cart, name='decreasecart'),
]


import torch
import numpy as np
from frac_brownian import frac_brownian

# Sampling

def fcir(r0, a, b, sigma, H, m, n, T, device=None, seed=123):
    """
        Inputs:
            r0: float tensor of shape (m,1), initial rates
            a: float tensor of shape (m), long term mean level
            b: float tensor of shape (m), speed of reversion
            sigma: float tensor of shape (m), instantaneous volatility
            H: float, Hurst exponent
            m: int, nb of trajs
            n: int, nb of points
            T: float, trajs generated between [0,T]
            device: torch device
            seed: int
        Outputs:
            dict of torch float tensor of shape (m,n): m fCIR trajectories of n points on an uniformly spaced grid on [0,T]
    """
    if seed is not None:
        torch.manual_seed(seed)
        torch.cuda.manual_seed(seed)

    delta_t = T/n*torch.ones(1, dtype=torch.float, device=device)
    fBm = frac_brownian(H, m, n, T, device, seed)
    fBm_increments = fBm[:,1:] - fBm[:,:-1]

    r = r0*torch.ones(m, n, dtype=torch.float, device=device)
    for i in range(1,n):
        r[:,i] = r[:,i-1] + a*delta_t*(b-r[:,i-1]) + sigma*torch.sqrt(torch.abs(r[:,i-1]))*fBm_increments[:,i-1]
    res = {
        'traj':r
    }
    return res


"""The module contains a base class for Mediator,
from which is inherited in all blockchain mediators.

Author: Jan Jakub Kubik (xkubik32)
Date: 14.3.2023
"""
import random
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional, Set

from base.logs import create_logger

class ActionObjectStore:
    """A container for storing objects associated with actions.

    The ActionObjectStore class provides a convenient way to store objects
    that are associated with specific actions. It allows adding and removing
    objects, retrieving objects for a given action, getting the list of all
    actions, and clearing the entire store.

    Attributes:
        _store (Dict[Any, List[Any]]): A dictionary containing lists of objects keyed by actions.
        _all_actions (List[Any]): A list of all actions in the store.
    """

    def __init__(self):
        """Initialize the ActionObjectStore with an empty store and an empty list of actions."""
        self._store: Dict[Any, List[Any]] = {}
        self._all_actions: List[Any] = []

    def add_object(self, action: Any, obj: Any = None) -> None:
        """Add an object associated with the given action to the store.

        Args:
            action (Any): The action to associate with the object.
            obj (Any, optional): The object to store. Defaults to None.
        """
        if action not in self._store:
            self._store[action] = [obj]
        else:
            self._store[action].append(obj)

        self._all_actions.append(action)

    def remove_object(self, action: Any, obj: Any = None) -> None:
        """Remove an object associated with the given action from the store.

        Args:
            action (Any): The action associated with the object.
            obj (Any, optional): The object to remove. Defaults to None.
        """
        if action in self._store and obj in self._store[action]:
            self._store[action].remove(obj)
            self._all_actions.remove(action)

            if not self._store[action]:
                del self._store[action]

    def get_objects(self, action: Any) -> List:
        """Retrieve a list of objects associated with the given action.

        Args:
            action (Any): The action to retrieve objects for.

        Returns:
            List: List of objects associated with the action.
        """
        return self._store.get(action, [])

    def get_actions(self) -> List:
        """Retrieve the list of all actions in the store.

        Returns:
            List: List of all actions.
        """
        return self._all_actions

    def clear(self) -> None:
        """Clear the store and the list of actions."""
        self._store.clear()
        self._all_actions.clear()

class SimulationManagerBase(ABC):
    """Abstract base class for all blockchain simulation managers."""

    def __init__(self, simulation_config: Dict[str, Any], blockchain: str):
        self.log = create_logger(blockchain)
        self.config: Dict[str, Any] = self.__call_parse_config(simulation_config)

    @abstractmethod
    def parse_config(self, simulation_config: Dict[str, Any]) -> Dict[str, Any]:
        """Parse the configuration for the simulation.

        Args:
            simulation_config (Dict[str, Any]): The simulation configuration dictionary.

        Returns:
            Dict[str, Any]: Parsed configuration dictionary.
        """
        raise NotImplementedError

    @abstractmethod
    def run(self) -> None:
        """Run the simulation."""
        raise NotImplementedError

    @abstractmethod
    def resolve_overrides(self) -> None:
        """Resolve the 'override' actions in the simulation."""
        raise NotImplementedError

    @abstractmethod
    def resolve_matches(self) -> None:
        """Resolve the 'match' actions in the simulation."""
        raise NotImplementedError

    @staticmethod
    def choose_leader(choices: List[Any], weights: List[float]) -> Any:
        """Select a leader for the current round according to the given weights.

        Args:
            choices (List[Any]): List of possible leaders.
            weights (List[float]): List of weights for each leader.

        Returns:
            Any: The selected leader.
        """
        return random.choices(choices, weights, k=1)[0]

    def validate_blockchain_config_keys(
        self, dictionary: Dict[str, Any], expected_keys: Set[str]
    ) -> None:
        """Validate top-level keys in the parsed simulation config.

        Args:
            dictionary (Dict[str, Any]): The dictionary to validate.
            expected_keys (Set[str]): The set of expected keys.
        """
        self.log.info("validating simulation config")
        dict_keys = set(dictionary.keys())
        if dict_keys != expected_keys:
            raise ValueError(
                f"You are missing or you have used redundant top-level keys in the YAML config."
                f" Please use just these keys: {expected_keys}"
            )

    def general_config_validations(
        self,
        simulation_config: Dict[str, Any],
        expected_keys_extra: Optional[List[str]] = (),
    ) -> Dict[str, Any]:
        """
        Validates the general configuration of a simulation.

        Args:
            simulation_config (Dict[str, Any]): The simulation configuration dictionary.
            expected_keys_extra (Optional[List[str]]): The extra expected keys to validate.
                                                       By default, it is an empty list.

        Raises:
            ValueError: If there is not exactly 1 honest miner or no selfish
            miners in the configuration.

        Returns:
            Dict[str, Any]: The validated simulation configuration dictionary.
        """
        # check main keys
        expected_keys: Set[str] = {
            "consensus_name",
            "miners",
            "simulation_mining_rounds",
        }
        for key in expected_keys_extra:
            expected_keys.add(key)

        sim_config: Dict[str, Any] = list(simulation_config.values())[0]
        self.validate_blockchain_config_keys(sim_config, expected_keys)

        miners: Dict[str, Any] = sim_config["miners"]
        if len(list(miners["honest"])) != 1:
            raise ValueError("You must setup exactly 1 honest miner")
        if len(list(miners["selfish"])) == 0:
            raise ValueError("You must setup at least 1 selfish miner")

        return sim_config

    def __call_parse_config(self, simulation_config: Dict[str, Any]) -> Dict[str, Any]:
        return self.parse_config(simulation_config)