# -*- coding: utf-8 -*-
import json
import datetime
import math
import re
import traceback
from copy import deepcopy
from decimal import Decimal
from functools import lru_cache

from django.apps import apps
from django.contrib import messages
from django.db import transaction
from django.forms.models import ModelFormMetaclass
from django.forms import *
from .fields import *
from django.http import HttpResponse, HttpResponseRedirect
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
from django.utils.text import slugify

from . import inputs
from .fields import *
from ..core.queryset import QuerySet
from sloth.api.exceptions import JsonReadyResponseException, ReadyResponseException, HtmlReadyResponseException
from ..utils import to_api_params, to_snake_case
from ..utils.formatter import format_value
from ..utils.http import FileResponse

ACTIONS = {}
EXPOSE = []

class PermissionChecker:

    def __init__(self, request, instance=None, instantiator=None, metaclass=None):
        self.request = request
        self.instance = instance
        self.instantiator = instantiator
        self.metaclass = metaclass

    def has_permission(self, user):
        return self and user

class ActionDefaultMetaClass:
    modal = True

class ActionMetaclass(ModelFormMetaclass):
    def __new__(mcs, name, bases, attrs):
        if 'Meta' in attrs:
            if hasattr(attrs['Meta'], 'model'):
                if isinstance(attrs['Meta'].model, str):
                    attrs['Meta'].model = apps.get_model(attrs['Meta'].model)
                bases += forms.ModelForm,
            else:
                bases += forms.Form,
            if not hasattr(attrs['Meta'], 'fields') and not hasattr(attrs['Meta'], 'exclude'):
                form_fields = []
                fieldsets = getattr(attrs['Meta'], 'fieldsets', {})
                if fieldsets:
                    for tuples in fieldsets.values():
                        for names in tuples:
                            if isinstance(names, str):
                                form_fields.append(names)
                            else:
                                form_fields.extend(names)
                    setattr(attrs['Meta'], 'fields', form_fields)
                else:
                    setattr(attrs['Meta'], 'exclude', ())
        else:
            bases += forms.Form,
            attrs['Meta'] = ActionDefaultMetaClass
        cls = super().__new__(mcs, name, bases, attrs)
        ACTIONS[name] = cls
        ACTIONS[to_snake_case(name)] = cls
        if 'ActionView' in [k.__name__ for k in bases]:
            EXPOSE.append(to_snake_case(name))
        return cls

class DecimalField(forms.DecimalField):
    def clean(self, value):
        if value:
            value = value.replace('.', '').replace(',', '.')
        value = super().clean(value)
        return value

class TextField(forms.CharField):
    def __init__(self, *args, **kwargs):
        kwargs.update(widget=forms.Textarea())
        super().__init__(*args, **kwargs)

class BooleanChoiceField(forms.ChoiceField):
    def __init__(self, *args, **kwargs):
        kwargs.update(widget=forms.Select(), choices=[['', ''], [1, 'Sim'], [0, 'Não']])
        super().__init__(*args, **kwargs)

    def clean(self, value):
        if value == '':
            if self.required:
                raise ValidationError('Selecione uma opção')
            return None
        return bool(int(value))

class RegionalDateWidget(DateInput):
    input_type = 'date'

    def render(self, name, value, attrs=None, renderer=None):
        if isinstance(value, datetime.date):
            value = value.isoformat()
        attrs = attrs or {}
        attrs.update({'autocomplete': 'off'})
        html = super().render(name, value, attrs)
        return mark_safe(html)

class RegionalDateTimeWidget(DateTimeInput):
    input_type = 'datetime-local'

    def render(self, name, value, attrs=None, renderer=None):
        if isinstance(value, datetime.datetime):
            value = value.isoformat().split('.')[0]
        attrs = attrs or {}
        attrs.update({'step': '1'})
        html = super().render(name, value, attrs)
        return mark_safe(html)

class Action(metaclass=ActionMetaclass):

    def __init__(self, *args, **kwargs):
        self.path = None
        self.request = kwargs.pop('request', None)
        self.instantiator = kwargs.pop('instantiator', None)
        self.queryset = kwargs.pop('queryset', None)
        self.instances = kwargs.pop('instances', None)
        self.metaclass = getattr(self, 'Meta')

        self.show_form = True
        self.can_be_closed = False
        self.can_be_reloaded = False
        self.content = dict(top=[], left=[], center=[], right=[], bottom=[], info=[], alert=[], danger=[])
        self.on_change_data = dict(show=[], hide=[], set=[], show_fieldset=[], hide_fieldset=[])

        if forms.ModelForm in self.__class__.__bases__:
            self.instance = kwargs.get('instance', None)
        else:
            self.instance = kwargs.pop('instance', None)

        if self.instance is None and self.instances is not None and self.instances.exists():
            self.instance = self.instances.first()

        if self.request.path.startswith('/api/') or self.request.path.startswith('/meta/'):
            if self.request.body and self.request.body.startswith(b'{') and self.request.body.endswith(b'}'):
                kwargs['data'] = json.loads(self.request.body)

        if self.has_url_posted_data():
            for k in self.request.GET:
                if k.startswith('post__'):
                    if 'data' not in kwargs:
                        kwargs['data'] = {}
                    kwargs['data'][k.split('__')[-1]] = self.request.GET[k]

        if 'data' not in kwargs:
            if self.get_api_name() in self.request.GET or self.get_api_name() in self.request.POST or not self.request.path.startswith('/app/'):
                # if self.base_fields or self.requires_confirmation():
                if self.request.method == 'GET' or self.requires_confirmation():
                    if self.get_method() == 'get':
                        data = self.request.GET or None
                    else:
                        data = self.request.POST or None
                else:
                    data = self.request.POST
                kwargs['data'] = data
                kwargs['files'] = self.request.FILES or None
            else:
                kwargs['data'] = None

        super().__init__(*args, **kwargs)
        if self.instance is not None and hasattr(self.instance, 'autouser') and not self.instance.autouser_id:
            self.instance.autouser = self.request.user
            if 'autouser' in self.fields:
                del self.fields['autouser']

        for name in self.fields:
            if name != 'data':
                setattr(self, name, self.initial.get(name, None))
        self.asynchronous = getattr(self.metaclass, 'asynchronous', None) and self.request.GET.get('synchronous') is None

        related_field_name = getattr(self.metaclass, 'related_field', None)
        if related_field_name:
            setattr(self.instance, related_field_name, self.instantiator)
            if related_field_name in self.fields:
                del self.fields[related_field_name]

        for field_name in self.fields:
            field = self.fields[field_name]
            if hasattr(field, 'queryset'):
                if getattr(field, 'username_lookup', None):
                    pks = list(field.queryset.filter(**{field.username_lookup: self.request.user}).values_list('pk', flat=True)[0:2])
                    if len(pks) == 1:
                        field.queryset = field.queryset.model.objects.filter(pk=pks[0])
                        field.initial = pks[0]
                        self.initial[field_name] = field.initial
                        # field.widget = forms.HiddenInput()
                        field.widget.attrs['class'] = '{} disabled'.format(field.widget.attrs.get('class', ''))
                        field.widget.attrs['readonly'] = 'readonly'
                else:
                    field.queryset = field.queryset#.contextualize(self.request).apply_role_lookups(self.request.user)

        self.response = {}
        self.fieldsets = {}
        self.one_to_one = {}
        self.one_to_many = {}

        confirmation = self.requires_confirmation()
        if confirmation:
            help_text = confirmation if isinstance(confirmation, str) else ''
            self.fields['confirmation'] = forms.BooleanField(
                label='', initial='on', required=False, help_text=help_text,
                widget=forms.HiddenInput()
            )

    @classmethod
    def get_api_doc(cls, detail=False):
        if detail and cls.base_fields:
            doc = []
            field_names = [field.label.lower() for field in cls.base_fields.values()]
            doc.append('Requer as seguintes informações: {}.'.format(', '.join(field_names)))
            return ' '.join(doc)
        return None

    def render(self, template_name, **context):
        return HttpResponse(render_to_string([template_name], context, request=self.request))

    def get_verbose_name(self):
        return self.get_metadata().get('name')

    def get_image(self):
        return self.get_metadata().get('image')

    def has_url_posted_data(self):
        return 'post__{}'.format(self.get_api_name()) in self.request.GET

    def closable(self, flag=True):
        self.can_be_closed = flag

    def reloadable(self, flag=True):
        self.can_be_reloaded = flag

    def info(self, text):
        if text:
            self.content['info'].append(text)

    def alert(self, text):
        if text:
            self.content['alert'].append(text)

    def danger(self, text):
        if text:
            self.content['danger'].append(text)

    def parameters(self):
        data = {}
        for token in self.request.path.split('/'):
            if '=' in token:
                k, v = token.split('=')
                data[k] = int(v) if v.isdigit() else v
        return data

    def parameter(self, name, default=None):
        return self.parameters().get(name, default)

    def objects(self, model_name):
        return apps.get_model(model_name).objects.queryset().contextualize(self.request).apply_role_lookups(self.request.user)

    def clear(self):
        self.show_form = False
        for k, v in self.content.items():
            if k != 'bottom':
                v.clear()

    def view(self):
        return None

    def append(self, item, position='center'):
        if hasattr(item, 'contextualize'):
            item.contextualize(self.request)
        self.content[position].append(item.html())

    def has_attr_permission(self, user, name):
        attr = getattr(self, 'has_{}_permission'.format(name), None)
        return attr is None or attr(user)

    def requires_confirmation(self):
        return getattr(self.metaclass, 'confirmation', False)

    @lru_cache
    def get_one_to_one_field_names(self):
        return self.instance.get_one_to_one_field_names() if self.instance else ()

    @lru_cache
    def get_one_to_many_field_names(self):
        return self.instance.get_one_to_many_field_names() if self.instance else ()

    def get_fieldsets(self):
        related_field = getattr(self.instance, 'related_field', None) if self.instance is not None else None
        if related_field and related_field in self.fields:
            del self.fields[related_field]
        fieldsets = getattr(self.metaclass, 'fieldsets', None)
        if fieldsets is None:
            fieldsets = {}
            if self.fields:
                field_names = [
                    name for name in self.fields.keys() if (
                            name not in self.get_one_to_one_field_names()
                            and name not in self.get_one_to_many_field_names()
                            and name not in ('confirmation', related_field)
                    )
                ]
                if field_names:
                    fieldsets[None] = field_names
        else:
            fieldsets = dict(fieldsets)
        return fieldsets

    def load_fieldsets(self):
        fieldsets = self.get_fieldsets()

        # extract one-to-one and one-to-many fields
        if self.instance:
            for name in list(self.fields):
                if name in self.get_one_to_one_field_names():
                    # remove one-to-one fields from the form
                    self.one_to_one[name] = self.fields.pop(name)
                if name in self.get_one_to_many_field_names():
                    # remove one-to-many fields from the form
                    self.one_to_many[name] = self.fields.pop(name)

        pop = []
        for name, names in fieldsets.items():
            if len(names) == 1 and (names[0] in self.one_to_one.keys() or names[0] in self.one_to_many.keys()):
                pop.append(name)
        for name in pop:
            del fieldsets[name]

        # configure one-to-one fields
        for one_to_one_field_name, one_to_one_field in self.one_to_one.items():
            field_list = []
            form_cls = one_to_one_field.queryset.model.add_form_cls()
            initial = one_to_one_field.queryset.model.objects.filter(
                pk=getattr(self.instance, '{}_id'.format(one_to_one_field_name))
            ).values(
                *form_cls.base_fields.keys()
            ).first() or {}
            key = one_to_one_field_name.upper()
            self.fields[key] = forms.BooleanField(
                required=one_to_one_field.required, initial=bool(initial) or one_to_one_field.required
            )
            self.fields[key].widget.attrs['class'] = 'field-controller'
            if one_to_one_field.required:
                self.fields[key].widget.attrs['class'] += ' d-none'
            for name, field in form_cls.base_fields.items():
                ont_to_one_key = '{}__{}'.format(one_to_one_field_name, name)
                field_list.append(ont_to_one_key)
                field.required = field.required and one_to_one_field.required or self.data.get(
                    one_to_one_field_name.upper()
                )
                field.widget.attrs['class'] = key
                self.fields[ont_to_one_key] = field
                self.initial[ont_to_one_key] = initial.get(name)

            # try to get field organization from form fieldsets if defined
            one_to_one_fieldsets = getattr(form_cls.Meta, 'fieldsets', None)
            if one_to_one_fieldsets is None:
                one_to_one_fieldsets = getattr(form_cls.Meta.model.metaclass(), 'fieldsets', None)
            if one_to_one_fieldsets is not None:
                field_list = []
                for fieldset in one_to_one_fieldsets.values():
                    for names in fieldset:
                        if isinstance(names, str):
                            field_list.append('{}__{}'.format(one_to_one_field_name, names))
                        else:
                            field_list.append(
                                ['{}__{}'.format(one_to_one_field_name, field_name) for field_name in names]
                            )
            field_list.append(one_to_one_field_name.upper())
            fieldsets[one_to_one_field.label] = field_list

        # configure one-to-many fields
        for one_to_many_field_name, one_to_many_field in self.one_to_many.items():
            field_list = []
            form_cls = one_to_many_field.queryset.model.add_form_cls()
            pks = []
            if self.instance.pk:
                pks.extend(getattr(self.instance, one_to_many_field_name).values_list('pk', flat=True))
            pks.extend(['' for _ in range(len(pks) + 1, one_to_many_field.max + 1)])
            for i, pk in enumerate(pks):
                initial = one_to_many_field.queryset.model.objects.filter(
                    pk=pk
                ).values(
                    *form_cls.base_fields.keys()
                ).first() if pk else {}
                key = '{}--{}'.format(one_to_many_field_name.upper(), i)
                required = i < one_to_many_field.min
                self.fields[key] = forms.CharField(
                    label='{} {}'.format(one_to_many_field.queryset.model.metaclass().verbose_name, i + 1),
                    required=required, initial=(pk or 'on') if required else pk, widget=forms.CheckboxInput()
                )
                self.fields[key].widget.attrs['class'] = 'field-controller'
                if required:
                    self.fields[key].widget.attrs['class'] += ' d-none'
                field_list.append(key)
                inline_field_list = []
                for name, field in form_cls.base_fields.items():
                    field = deepcopy(field)
                    one_to_many_key = '{}__{}__{}'.format(one_to_many_field_name, name, i)
                    inline_field_list.append(one_to_many_key)
                    field.required = field.required and required or False
                    field.widget.attrs['class'] = key
                    self.fields[one_to_many_key] = field
                    self.initial[one_to_many_key] = initial.get(name)

                field_list.append(inline_field_list)
            fieldsets[one_to_many_field.label] = field_list
        self.fieldsets = fieldsets
        self.parse_fieldsets()

    def parse_fieldsets(self):
        # configure ordinary fields
        for title, names in self.fieldsets.items():
            field_list = []
            for name in names:
                if isinstance(name, tuple) or isinstance(name, list):
                    for _name in name:
                        if _name in self.fields:
                            if not isinstance(self.fields[_name].widget, forms.HiddenInput):
                                field_list.append(dict(name=_name, width=100 // len(name)))
                else:
                    if name in self.fields:
                        if not isinstance(self.fields[name].widget, forms.HiddenInput):
                            field_list.append(dict(name=name, width=100))
            if field_list:
                self.fieldsets[title] = field_list

    def get_api_params(self):
        return to_api_params(self.fields.items())

    def save(self, *args, **kwargs):
        if hasattr(self.instance, '__roles__'):
            with transaction.atomic():
                self._save()
        else:
            self._save()

    def _save(self, *args, **kwargs):

        if hasattr(self.instance, 'pre_save'):
            self.instance.pre_save()

        # save one-to-one fields
        for name in self.one_to_one:
            instance = getattr(self.instance, name)
            if self.data.get(name.upper()):  # if checkbox is checked
                instance = instance or self.one_to_one[name].queryset.model()
                for field_name in self.fields:
                    if field_name.split('__')[0] == name:
                        setattr(instance, field_name.split('__')[1], self.cleaned_data[field_name])
                instance.save()
                setattr(self.instance, name, instance)
            else:  # if checkbox is NOT checked
                if instance:
                    instance.delete()
                setattr(self.instance, name, None)

        # save
        if hasattr(super(), 'save'):
            super().save(*args, **kwargs)

        # save one-to-many fields
        for name in self.one_to_many:
            qs = getattr(self.instance, name)
            pks = list(qs.values_list('pk', flat=True))
            for i in range(0, 10):
                key = '{}--{}'.format(name.upper(), i)
                pk = self.data.get(key)
                if pk:  # if checkbox is checked
                    if pk == 'on':
                        instance = qs.model()
                    else:
                        pks.remove(int(pk))
                        instance = qs.get(pk=pk)
                    for field_name in self.fields:
                        if field_name.startswith('{}__'.format(name)) and field_name.endswith('__{}'.format(i)):
                            setattr(instance, field_name.split('__')[1], self.cleaned_data[field_name])
                    instance.save()
                    qs.add(instance)
            qs.filter(pk__in=pks).delete()

        if hasattr(self.instance, 'post_save'):
            self.instance.post_save()

    def serialize(self, wrap=False):
        if self.response:
            return self.response
        if wrap:
            data = dict(type='form')
            form_fields = {}
            for field_name in self.fields:
                field = self.fields[field_name]
                form_fields[field_name] = dict(
                    label=field.label,
                    name=field_name,
                    type=type(field).__name__.replace('Field', '').lower(),
                    required=field.required,
                    value=self.data.get(field_name)
                )
            data.update(self.get_metadata())
            if hasattr(self, 'get_verbose_name'):
                data['name'] = hasattr(self, 'get_verbose_name')
            data.update(fields=form_fields, errors=self.errors)
            return data
        else:
            data = {field_name: self.fields[field_name].initial for field_name in self.fields}
            return data

    @lru_cache()
    def get_on_change_fields(self):
        on_change = []
        for attr_name in dir(self):
            if attr_name.startswith('on_') and attr_name.endswith('_change'):
                field_name = attr_name[3:-7]
                on_change.append(field_name)
        return on_change

    def get_allowed_attrs(self, recursive=True):
        return []

    @classmethod
    def get_api_name(cls):
        return to_snake_case(cls.__name__)

    @classmethod
    @lru_cache
    def get_metadata(cls, path=None, target=None):
        metaclass = getattr(cls, 'Meta', None)
        if metaclass:
            target = target
            name = getattr(metaclass, 'verbose_name', re.sub("([a-z])([A-Z])", "\g<1> \g<2>", cls.__name__))
            submit = getattr(metaclass, 'submit_label', name)
            icon = getattr(metaclass, 'icon', None)
            ajax = getattr(metaclass, 'ajax', True)
            modal = getattr(metaclass, 'modal', True)
            style = getattr(metaclass, 'style', 'primary')
            method = getattr(metaclass, 'method', 'post')
            auto_reload = getattr(metaclass, 'auto_reload', None)
            image = getattr(metaclass, 'image', None)
        else:
            name, submit, icon, ajax, modal, style, method, auto_reload, image = (
                'Enviar', 'Enviar', None, True, 'modal', 'primary', 'get', None, None
            )
        if path:
            path, *params = path.split('?')
            if target in ('queryset', 'instance'):
                path = '{}{{id}}/{}/'.format(path, cls.get_api_name())
            else:
                path = '{}{}/'.format(path, cls.get_api_name())
            if params:
                path = '{}?{}'.format(path, params[0])
        metadata = dict(
            type='form', key=cls.get_api_name(), name=name, submit=submit, target=target,
            method=method, icon=icon, style=style, ajax=ajax, path=path, modal=modal,
            auto_reload=auto_reload, image=image
        )
        return metadata

    def get_method(self):
        return getattr(self.metaclass, 'method', 'post') if hasattr(self, 'Meta') else 'post'

    def get_instances(self):
        if self.instances is not None:
            return self.instances
        elif self.queryset is not None:
            return self.queryset
        elif self.instance:
            return type(self.instance).objects.filter(pk=self.instance.pk)
        return []

    def is_modal(self):
        return getattr(self.metaclass, 'modal', True) if hasattr(self, 'Meta') else True

    def has_permission(self, user):
        return user.is_superuser

    def check_permission(self, user):
        return user.is_superuser or self.has_permission(user)

    @classmethod
    def check_fake_permission(cls, request, instance=None, instantiator=None):
        if request:  # and not request.user.is_superuser
            checker = PermissionChecker(request, instance, instantiator, getattr(cls, 'Meta', None))
            has_permission = cls.has_permission(checker, request.user)
            return has_permission
            ### return cls.check_permission(checker, request.user) if has_permission is None else has_permission
        return True

    def __str__(self):
        return self.html()

    def get_alternative_links(self):
        return []

    def html(self):

        for name, field in self.fields.items():
            classes = field.widget.attrs.get('class', '').split()
            if isinstance(field.widget, forms.CheckboxInput):
                classes.append('form-check-input')
            elif isinstance(field.widget, forms.widgets.Input):
                classes.append('form-control')

            if isinstance(field, forms.DateField):
                field.widget = RegionalDateWidget()
                classes.append('date-input')
                if name in self.initial and self.initial[name] and isinstance(self.initial[name], str) and '/' in self.initial[name]:
                    self.initial[name] = datetime.datetime.strptime(self.initial[name], '%d/%m/%Y').strftime('%Y-%m-%m')

            if isinstance(field, forms.DateTimeField):
                field.widget = RegionalDateTimeWidget()
                classes.append('date-time-input')
                if name in self.initial and self.initial[name] and isinstance(self.initial[name], str) and '/' in self.initial[name]:
                    self.initial[name] = datetime.datetime.strptime(self.initial[name], '%d/%m/%Y').strftime('%Y-%m-%m %H:%M')

            if isinstance(field, forms.DecimalField):
                field.widget.input_type = 'text'
                field.widget.rmask = getattr(field.widget, 'rmask', '#.##0,00')
                if name in self.initial and self.initial[name] is not None:
                    self.initial[name] =  Decimal('%.2f' % self.initial[name])

            if isinstance(field, forms.ImageField):
                classes.append('image-input')

            if isinstance(field, forms.ModelChoiceField) and isinstance(field.widget, Select):
                initial = self.initial.get(name)
                pks = []
                if initial:
                    if isinstance(initial, int):
                        pks.append(initial)
                    else:
                        if isinstance(initial[0], int):
                            pks.extend([pk for pk in initial])
                        else:
                            pks.extend([obj.pk for obj in initial])
                if self.data:
                    pks = [pk for pk in self.data.getlist(name) if pk]
                if getattr(field, 'picker', None) is None:
                    field.queryset = field.queryset.filter(pk__in=pks) if pks else field.queryset.none()
                field.widget.attrs['data-choices-url'] = '{}{}action_choices={}'.format(
                    self.get_full_path(), '&' if '?' in self.get_full_path() else '?', name
                )

            if getattr(field.widget, 'mask', None):
                classes.append('masked-input')
                field.widget.attrs['data-reverse'] = 'false'
                field.widget.attrs['data-mask'] = getattr(field.widget, 'mask')
            if getattr(field.widget, 'rmask', None):
                classes.append('masked-input')
                field.widget.attrs['data-reverse'] = 'true'
                field.widget.attrs['data-mask'] = getattr(field.widget, 'rmask')
            if getattr(field.widget, 'formatted', False):
                classes.append('html-input')

            if hasattr(field, 'picker'):
                grouper = field.picker if isinstance(field.picker, str) else None
                if isinstance(field, forms.ModelMultipleChoiceField):
                    field.widget = inputs.MultiplePickInput(field.queryset, grouper=grouper)
                else:
                    field.widget = inputs.PickInput(field.queryset, grouper=grouper)

            if getattr(field, 'addable', False):
                has_permission = field.queryset.model().has_add_permission(self.request.user)
                has_permission = has_permission or field.queryset.model().has_permission(self.request.user)
                help_text = '<div>{}</div>'.format(field.help_text) if field.help_text else ''
                link = '<a style="text-decoration:none" class="popup" href="/app/dashboard/{}/{}/add/">Adicionar</a>'.format(
                    field.queryset.model.metaclass().app_label, field.queryset.model.metaclass().model_name
                )
                help_text = '<div style="float:right">{}</div>'.format(link) + help_text
                if has_permission:
                    field.help_text = help_text

            field.widget.attrs['class'] = ' '.join(classes)
        return mark_safe(
            render_to_string(
                ['dashboard/form.html'], dict(
                    self=self, fieldsets=self.fieldsets
                ),
                request=self.request
            )
        )

    def show(self, *names):
        for name in names:
            if name.islower():
                if name in self.on_change_data['hide']:
                    self.on_change_data['hide'].remove(name)
                if name not in self.on_change_data['show']:
                    self.on_change_data['show'].append(name)
            else:
                name = slugify(name)
                if name in self.on_change_data['hide_fieldset']:
                    self.on_change_data['hide_fieldset'].remove(name)
                if name not in self.on_change_data['show_fieldset']:
                    self.on_change_data['show_fieldset'].append(name)

    def hide(self, *names):
        for name in names:
            if name.islower():
                if name in self.on_change_data['show']:
                    self.on_change_data['show'].remove(name)
                if name not in self.on_change_data['hide']:
                    self.on_change_data['hide'].append(name)
            else:
                name = slugify(name)
                if name in self.on_change_data['show_fieldset']:
                    self.on_change_data['show_fieldset'].remove(name)
                if name not in self.on_change_data['hide_fieldset']:
                    self.on_change_data['hide_fieldset'].append(name)

    def set(self, **kwargs):
        for k, v in kwargs.items():
            if hasattr(v, 'pk'):
                value = v.pk
                text = str(v)
            else:
                value = format_value(v)
                text = None
            self.on_change_data['set'].append(dict(name=k, value=value, text=text))

    def check_ouput(self, output, submit=False):
        from ..core.valueset import ValueSet
        position = 'bottom' if submit else 'center'
        if type(output) == dict:
            if self.request.path.startswith('/app/'):
                template_name = 'actions/{}.html'.format(self.get_api_name())
                self.content[position].append(render_to_string([template_name], output, request=self.request))
            else:
                raise JsonReadyResponseException(output)
        elif type(output) == str and output[-5:].split('.')[-1] in FileResponse.CONTENT_TYPES.keys():
            raise ReadyResponseException(FileResponse(output))
        elif type(output) in (str, int, float, Decimal, datetime.date):
            raise ReadyResponseException(HttpResponse(str(output)))
        elif isinstance(output, HttpResponse):
            raise ReadyResponseException(output)
        elif isinstance(output, ValueSet) or isinstance(output, QuerySet):
            if submit:
                path = '{}{}/'.format(self.request.path, 'submit') if self.request.POST else None
            else:
                path = '{}{}/'.format(self.request.path, 'view')
            self.content[position].append(output.readonly().contextualize(self.request).html(path=path))
        elif output is not None:
            raise Exception()
        if self.request.path.startswith('/app/') and self.response and submit:
            js = '<script>{}</script>'
            display_messages = True
            url = self.response.get('url')
            if self.response.get('dispose'):
                js = js.format('fade{}({});'.format(self.get_metadata().get('key'), self.response.get('dispose')))
            elif url == '.':
                if 'modal' in self.request.GET:
                    js = js.format('$(document).popup("{}");'.format(self.request.path))
                else:
                    js = js.format('$(document).refresh([]);'.format(self.get_metadata().get('key')))
            elif url == '..':
                display_messages = 'modal' in self.request.GET
                js = js.format('$(document).back().refresh([]);')
            elif url:
                display_messages = False
                js = js.format('$(document).redirect("{}");'.format(self.response['url']))
            html = render_to_string('dashboard/messages.html', request=self.request) if display_messages else ''
            raise ReadyResponseException(HttpResponse('<!---->{}{}<!---->'.format(js, html)))

        if self.request.path.startswith('/app/') and self.response and not submit:
            stack = self.request.session.get('stack', [])
            url = self.response.get('url')
            if url in ('.', '..') and len(stack) > 1:
                url = stack[-2]
            raise ReadyResponseException(HttpResponseRedirect(url))

        return output

    def is_valid(self):
        if self.asynchronous:
            return False
        self.check_ouput(self.view())
        self.load_fieldsets()
        if 'action_choices' in self.request.GET:
            raise JsonReadyResponseException(
                self.choices(self.request.GET['action_choices'], q=self.request.GET.get('term'))
            )
        if 'on_change_field' in self.request.POST:
            for data in self.on_change_data.values():
                data.clear()
            field_name = self.request.POST['on_change_field']
            value = self.request.POST.get('on_change_value')
            if value == 'true':
                value = True
            if value == 'false':
                value = False
            if value == 'unknown':
                value = None
            getattr(self, 'on_{}_change'.format(field_name))(value)
            raise JsonReadyResponseException(self.on_change_data)
        is_valid = super().is_valid()
        if not is_valid and not self.request.path.startswith('/app/'):
            raise JsonReadyResponseException(dict(errors=self.errors))
        return is_valid

    def choices(self, field_name, q=None):
        field = self.fields[field_name]
        if self.__class__.__name__ in ('Add', 'Edit'):
            attr = getattr(self.instance, 'get_{}_queryset'.format(field_name), None)
            if attr:
                for name in self.fields:
                    if isinstance(self.fields[name], MultipleChoiceField):
                        value = self.request.GET.getlist(name)
                    if isinstance(self.fields[name], ModelMultipleChoiceField):
                        value = self.request.GET.getlist(name)
                    else:
                        value = self.request.GET.get(name)
                        if value:
                            setattr(self.instance, name, self.fields[name].clean(value))
        else:
            attr = getattr(self, 'get_{}_queryset'.format(field_name), None)
        self.data.update(self.request.GET)
        qs = field.queryset if attr is None else attr(field.queryset)
        # qs = qs.contextualize(self.request).apply_role_lookups(self.request.user)
        total = qs.count()
        qs = qs.search(q=q) if q else qs
        items = [dict(id=value.id, text=str(value), html=value.get_select_display()) for value in qs[0:25]]
        return dict(total=total, page=1, pages=math.ceil((1.0 * total) / 25), q=q, items=items )

    def dispose(self, milleseconds=2000):
        self.response.update(dispose=milleseconds)

    def reload(self):
        return self.redirect('.')

    def message(self, text='Ação realizada com sucesso.', style='success', milleseconds=60000):
        level = dict(success=messages.SUCCESS, warning=messages.WARNING, info=messages.INFO)[style]
        if self.request.path.startswith('/app/'):
            messages.add_message(self.request, level, text)
        elif self.request.path.startswith('/meta/'):
            self.response.update(message=dict(text=text, style=style, milleseconds=milleseconds))
        else:
            self.response.update(message=text)

    def redirect(self, url=None):
        if url is None:
            url = '..' if getattr(self, 'fields', None) or self.is_modal() else '.'
        if not self.request.path.startswith('/api/'):
            self.response.update(type='redirect', url=url)
        if self.request.path.startswith('/app') and not self.get_metadata()['ajax']:
            raise ReadyResponseException(HttpResponseRedirect(url))

    def run(self, *tasks):
        for task in tasks:
            task.start(self.request)
        if len(tasks) > 1:
            self.redirect()
        else:
            self.redirect('/app/dashboard/api/task/{}/'.format(task.task_id))

    def submit(self):
        if self.instances:
            for instance in self.instances:
                self.instance = instance
                if self.has_permission(self.request.user):
                    self._post_clean()
                    self.save()
        else:
            self.save()
        self.message()
        self.redirect()

    def process(self):
        # print(self.request.path, {k:v for k, v in self.data.items() if k not in ['csrfmiddlewaretoken', self.get_metadata()['key']]})
        try:
            return self.check_ouput(self.submit(), True)
        except forms.ValidationError as e:
            if self.request.path.startswith('/app/'):
                message = 'Corrija os erros indicados no formulário'
                messages.add_message(self.request, messages.WARNING, message)
            self.add_error(None, e.message)
        except BaseException as e:
            if isinstance(e, ReadyResponseException):
                raise e
            if isinstance(e, JsonReadyResponseException):
                raise e
            if isinstance(e, HtmlReadyResponseException):
                raise e
            traceback.print_exc()
            message = 'Ocorreu um erro no servidor: {}'.format(e)
            if self.request.path.startswith('/app/'):
                messages.add_message(self.request, messages.WARNING, message)
            self.add_error(None, message)

    @classmethod
    def get_attr_metadata(cls, lookup):
        attr = getattr(cls, lookup)
        template = getattr(attr, '__template__', None)
        metadata = getattr(attr, '__metadata__', None)
        if template:
            if not template.endswith('.html'):
                template = '{}.html'.format(template)
            if not template.startswith('.html'):
                template = 'renderers/{}'.format(template)
        return getattr(attr, '__verbose_name__', lookup), False, template, metadata

    def value_set(self, *names):
        from sloth.core.base import ValueSet
        return ValueSet(self, names)

    @classmethod
    @lru_cache
    def action_form_cls(cls, action):
        return ACTIONS.get(action)

    def should_display_buttons(self):
        return self.fields or self.submit.__func__ != Action.submit

    def get_full_path(self):
        return self.path or self.request.get_full_path()

    def contextualize(self, request):
        return self

    def apply_role_lookups(self, user):
        return self

    def send_mail(self, to, subject, content, from_email=None):
        from sloth.api.models import Email
        Email.objects.send(to, subject, content, from_email)

    @classmethod
    def has_custom_view_method(cls):
        return not cls.view == Action.view

    @classmethod
    def has_custom_submit_method(cls):
        return not cls.submit == Action.submit

class ActionView(Action):
    pass


# -*- coding: utf-8 -*-

import os
import requests
import json
import time
from cqhttp import CQHttp
# 引入时间调度器 apscheduler 的 BlockingScheduler
from apscheduler.schedulers.blocking import BlockingScheduler

# bot = CQHttp(api_root='http://127.0.0.1:5701/')

# 创建调度器实例
sched = BlockingScheduler()
interval_delay = 120

header = {
	"Host": "api.amemv.com",
	"Connection": "keep-alive",
	"Accept-Encoding": "gzip",
	"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"
}

def load_user_config():
	with open('config.json','rb') as f:
		config = json.load(f)
		return config

def get_latest_tiktok_id(config):
	nickname = config["name"]
	for i in init_data:
		if i["nickname"] == nickname:
			return i["latest_tiktok_id"]

def update_latest_tiktok_id(config, latest_tiktok_id):
	nickname = config["name"]
	for i in init_data:
		if i["nickname"] == nickname:
			i["latest_tiktok_id"] = latest_tiktok_id

def get_tiktok_list(sec_uid):
	video_url = 'https://www.iesdouyin.com/web/api/v2/aweme/post/?{0}'
	video_form = {
		"sec_uid": sec_uid,
		"count":"21",
		"max_cursor":"0",
		"aid":"1128",
		"_signature": '4hIiBAAAg525HWk-tq3rV-ISIh', # signature
		"dytk": ''# dytk
	}
	url = video_url.format(
        '&'.join([key + '=' + video_form[key] for key in video_form]))
	response = requests.get(url, headers=header).json()
	tiktok_list = response["aweme_list"]
	return tiktok_list

def monitor_worker(config):
	new_tiktok_list = []
	time_record = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(time.time()))
	print("开始查询：" + time_record)
	msg_queue = []
	# 获取用户数据
	tiktok_list = get_tiktok_list(config['sec_uid'])

	# 最后一次获取的抖音的id
	if len(tiktok_list) == 0:
		print(str(config["name"]) + "未获取到数据，请检查用户是否发过抖音")
	else:
		msg = str(config["name"]) + "：共有"+str(len(tiktok_list))+"条抖音"
		print(msg)
	msg = ""
	latest_tiktok_id = get_latest_tiktok_id(config)
	for i in tiktok_list:
		# aweme_id = 当前抖音的id
		aweme_id = i["aweme_id"]
		if int(aweme_id) > int(latest_tiktok_id):
			new_tiktok_list.append(i)
			update_latest_tiktok_id(config, aweme_id)

	if tiktok_list:
		print("发现" + str(len(new_tiktok_list)) + "条新抖音\n")
		for i in new_tiktok_list:
			share_desc = i["desc"]
			cover_img = "https://p9-dy.byteimg.com/img/" + i["video"]["cover"]["uri"] + "~c5_300x400.jpg"
			play_addr = "https://aweme.snssdk.com/aweme/v1/play/?video_id=" + i["video"]["play_addr"]["uri"] + "&line=0"
			msg = [{'type': 'at', 'data': {'qq': str(config['at'])}},
					{'type': 'text', 'data': {'text': '\n%s更新抖音啦！\n标题：%s\n封面：\n' % (config["name"],share_desc)}},
					{'type': 'image','data': {'file': cover_img}},
					{'type': 'text', 'data': {'text': '\n链接：%s\n' % play_addr}}]
			msg_queue.append(msg)

	else:
		print("未发现更新\n")
	return msg_queue

def tiktok_monitor():
	try:
		time_record = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(time.time()))
		print(time_record, 'Monitoring Tiktok ...')
		for config in configs:
			msg_queue = monitor_worker(config)
			if len(msg_queue) > 0:
				for msg in msg_queue:
					bot.send_group_msg_async(group_id=config['qq_group'], message=msg, auto_escape=False)
					time.sleep(0.1)
	except Exception as e:
		print("ERROR When monitoring %s" % e)
	finally:
		pass

try:
	sched.add_job(
	    tiktok_monitor, 'interval', seconds=interval_delay,
	    misfire_grace_time=interval_delay, coalesce=True, max_instances=15)
except Exception as e:
	print(e)
# 开始调度任务

def init_task():
	for config in configs:
		sec_uid = config["sec_uid"]
		latest_tiktok_id = get_tiktok_list(sec_uid)[0]["aweme_id"]
		d = {}
		d["nickname"] = config["name"]
		d["sec_uid"] = sec_uid
		d["latest_tiktok_id"] = latest_tiktok_id
		init_data.append(d)

if __name__ == '__main__':
	init_data = []
	configs = load_user_config()
	init_task()
	sched.start()
	print(init_data)


def reverseVowels(s):
        """
        :type s: str
        :rtype: str
        """
        s=str(s)
        vow=[]
        allvowels=('a','A','e','E','i','I','o','O','u','U')
        for e in s:
                if e in allvowels:

                        vow.append(e)

        print(vow)
        vow.reverse()
        print(vow)
        j=0
        m=""
        for i in range(len(s)):
                if s[i] in allvowels:
                        m=m+vow[j]
                        j+=1

                else:
                        m=m+s[i]

        return m

ans=reverseVowels("rashi dashore")
print(ans)

"""
Given a string s, reverse only all the vowels in the string and return it.

The vowels are 'a', 'e', 'i', 'o', and 'u', and they can appear in both lower and upper cases, more than once.

Example 1:

Input: s = "hello"
Output: "holle"
Example 2:

Input: s = "leetcode"
Output: "leotcede"
"""


# Доопрацюйте класс Triangle таким чином, щоб він підтримував інтерфейс ітератора.
# Ітератор повинен віддавати сторони трикутника (обʼєкт класу Line)

class Point:
    crd_x = 0
    crd_y = 0
    crd_z = 0

    def __init__(self, init_x, init_y, init_z):
        self.x = init_x
        self.y = init_y
        self.z = init_z

    @property
    def x(self):
        return self.crd_x

    @x.setter
    def x(self, new_x):
        if not isinstance(new_x, (int, float)):
            raise TypeError
        self.crd_x = new_x

    @property
    def y(self):
        return self.crd_y

    @y.setter
    def y(self, new_y):
        if not isinstance(new_y, (int, float)):
            raise TypeError
        self.crd_y = new_y

    @property
    def z(self):
        return self.crd_z

    @z.setter
    def z(self, new_z):
        if not isinstance(new_z, (int, float)):
            raise TypeError
        self.crd_z = new_z

class Line:
    point_1 = None
    point_2 = None

    def __init__(self, init_p1, init_p2):
        self.p1 = init_p1
        self.p2 = init_p2

    @property
    def p1(self):
        return self.point_1

    @p1.setter
    def p1(self, new_1):
        if not isinstance(new_1, Point):
            raise TypeError
        self.point_1 = new_1

    @property
    def p2(self):
        return self.point_2

    @p2.setter
    def p2(self, new_2):
        if not isinstance(new_2, Point):
            raise TypeError
        self.point_2 = new_2

    @property
    def line_length(self):
        '''
        Функция расчитывает длину линии
        :return: Длина линии в формате Float
        '''
        res = ((((self.point_1.crd_x - self.point_2.crd_x) ** 2) + ((self.point_1.crd_y - self.point_2.crd_y) ** 2)) +
               ((self.point_1.crd_z - self.point_2.crd_z) ** 2)) ** 0.5
        return res

class Triangle:
    point_1 = None
    point_2 = None
    point_3 = None
    line_1 = None
    line_2 = None
    line_3 = None
    _idx = 0
    _val = []

    def __init__(self, init_p1, init_p2, init_p3):
        self.p1 = init_p1
        self.p2 = init_p2
        self.p3 = init_p3
        self.line_1 = Line(init_p1=self.point_1, init_p2=self.point_2)
        self.line_2 = Line(init_p1=self.point_2, init_p2=self.point_3)
        self.line_3 = Line(init_p1=self.point_1, init_p2=self.point_3)

    def __iter__(self):
        self._val = [getattr(self, name) for name in dir(self) if name.startswith('line')]
        return self

    def __next__(self):
        try:
            res = self._val[self._idx]
        except IndexError:
            raise StopIteration
        else:
            self._idx += 1
            return res

    @property
    def p1(self):
        return self.point_1

    @p1.setter
    def p1(self, new_1):
        if not isinstance(new_1, Point):
            raise TypeError
        self.point_1 = new_1

    @property
    def p2(self):
        return self.point_2

    @p2.setter
    def p2(self, new_2):
        if not isinstance(new_2, Point):
            raise TypeError
        self.point_2 = new_2

    @property
    def p3(self):
        return self.point_3

    @p3.setter
    def p3(self, new_3):
        if not isinstance(new_3, Point):
            raise TypeError
        self.point_3 = new_3

    @property
    def triangle_area(self):
        """
        Расчёт площади треугольника по формуле Герона
        :return: Площадь треугольника в формате Float
        """
        len1 = self.line_1.line_length
        len2 = self.line_2.line_length
        len3 = self.line_3.line_length

        p = (len1 + len2 + len3) / 2
        area = ((p - len1) * (p - len2) * (p - len3)) ** 0.5
        return area

a = Point(init_x=0, init_y=0, init_z=0)
b = Point(init_x=3, init_y=4, init_z=0)
c = Point(init_x=0, init_y=1, init_z=0)

ab = Line(init_p1=a, init_p2=b)

abc = Triangle(init_p1=a, init_p2=b, init_p3=c)

print(a)
print(ab)
print(abc)
print(type(abc.point_1))
print(type(abc.line_1))
print(ab.line_length)
print(abc.triangle_area)

for i in abc:
    print(i.line_length)
    print(type(i))


alphabet = "abcdefghijklmnopqrstuvwxyz"

class Scrambler():
    """
    Class to represent a rotor in the machine.
    """
    def __init__(self, mapping, step_orientation=[0], orientation=0):
        self.orientation = orientation  # integer representing current orientation of scrambler
        self.m = mapping  # list of numbers specifying how to map from input to output characters (by addition)
        self.inverse_m = self.calculate_inverse_m()  # list representing base mapping of scrambler in reverse direction
        self.step_orientation = step_orientation  # tuple of orientations AFTER has caused next rotor to step on

    def calculate_inverse_m(self):
        """
        From the original mapping, work out what the mapping is when you pass a character through in the other direction
        ie on the way back from the reflector
        """
        inverse_m = [0]*len(alphabet)  # initialise it at a list of zeros
        for i in range(len(alphabet)):
            result = self.m[i]
            new_map = len(alphabet) - result
            inverse_m[(result+i) % len(alphabet)] = new_map
        return inverse_m

    def encrypt_char_forward(self, integer):
        """
        Calculate what happens when you pass a single character, represented as integer, through the scrambler
        """
        current_wiring_f = self.m[self.orientation:] + self.m[:self.orientation]
        new_int = (integer + current_wiring_f[integer]) % len(alphabet)
        return new_int

    def encrypt_char_backward(self, integer):
        """
        Calculate what happens when you pass a single character, represented as integer, through the scrambler backwards
        """
        current_wiring_b = self.inverse_m[self.orientation:] + self.inverse_m[:self.orientation]
        new_int = (integer + current_wiring_b[integer]) % len(alphabet)
        return new_int

    def display_mapping(self):  # prints out the alphabetic mapping (for debugging)
        cipher = ""
        for i in range(len(alphabet)):
            cipher += alphabet[self.encrypt_char_forward(i)]
        print(alphabet)
        print(cipher)

class PairMap:
    """
    Superclass for things that swap pairs of characters (the reflector and the plugboard)
    """
    def __init__(self, mapping):
        self.m = mapping

    def encrypt_char(self, integer):
        """
        Calculate what happens when you pass a single character, represented as integer, through the reflector/plugboard
        """
        new_int = (integer + self.m[integer]) % len(alphabet)
        return new_int

    def display_mapping(self):  # prints out the alphabetic mapping (for debugging)
        cipher = ""
        for i in range(len(alphabet)):
            cipher += alphabet[self.encrypt_char(i)]
        print(alphabet)
        print(cipher)

class Reflector(PairMap):
    def __init__(self, mapping):
        PairMap.__init__(self, mapping)
        self.check = self.check_mapping()

    def check_mapping(self):
        """
        Check that the mapping is a valid reflector, ie swaps pairs of characters
        """
        check = True
        for i in range(len(self.m)):
            maps_to = (i + self.m[i]) % len(self.m)
            if (maps_to + self.m[maps_to]) % len(self.m) != i:
                check = False
        return check

class Plugboard(PairMap):  # note directionality is irrelevant for plugboard!
    def __init__(self, mapping):
        PairMap.__init__(self, mapping)
        self.check = self.check_mapping()

    def check_mapping(self):
        """
        Check that the plugboard is valid, ie swaps pairs of characters
        """
        check = True
        for i in range(len(self.m)):
            if self.m[i] != 0:
                maps_to = (i + self.m[i]) % len(self.m)
                if (maps_to + self.m[maps_to]) % len(self.m) != i:
                    check = False
        return check

class Machine:
    """
    Class to represent a whole enigma machine, including what scramblers it contains, reflector and plugboard settings
    """
    def __init__(self, scrambler_list, reflector=Reflector([0]*26), plugboard=Plugboard([0]*26)):
        self.s = scrambler_list
        self.ref = reflector
        self.plug = plugboard

    def increment_scramblers(self):
        """
        Step on the scramblers. Always step the first, step the others if pushed on by the previous
        """
        for i in range(len(self.s)):
            self.s[i].orientation = (self.s[i].orientation + 1) % len(alphabet)  # increment orientation of s[i]
            if self.s[i].orientation not in self.s[i].step_orientation:  # unless this means moving past push point
                break

    def loop_scramblers_f(self, num):
        """
        Pass a character forward through however many scramblers there are in the machine
        """
        for i in range(len(self.s)):
            num = self.s[i].encrypt_char_forward(num)
        return num

    def loops_scramblers_b(self, num):
        """
        Pass a character back through however many scramblers there are in the machine
        """
        for i in range(len(self.s)):
            num = self.s[len(self.s)-1 - i].encrypt_char_backward(num)
        return num

    def encrypt(self, plaintext):
        """
        Do encryption!
        :param plaintext: plaintext message, String
        :return:  ciphertext message, String
        """
        ciphertext = ""
        for c in plaintext:
            self.increment_scramblers()
            initial_no = alphabet.find(c)  # map the letter to its equivalent integer in the alphabet
            if c == " ":
                ciphertext += " "
            elif initial_no == -1:
                ciphertext += "*"
            else:
                num = self.plug.encrypt_char(initial_no)  # plugboard forward
                num = self.loop_scramblers_f(num)  # scrambler(s) forward
                if self.ref.m != [0]*len(alphabet):  # not null
                    num = self.ref.encrypt_char(num)  # reflector
                    num = self.loops_scramblers_b(num)  # scramblers backward
                    num = self.plug.encrypt_char(num)  # plugboard backward
                    ciphertext += alphabet[num]  # map from integer back to letter using alphabet, add to ciphertext str
                else:
                    ciphertext += alphabet[num]  # map from integer back to letter using alphabet, add to ciphertext str
        return ciphertext

# saved examples of real wartime scramblers, reflectors
si = Scrambler([4, 9, 10, 2, 7, 1, 23, 9, 13, 16, 3, 8, 2, 9, 10, 18, 7, 3, 0, 22, 6, 13, 5, 20, 4, 10], [17])
sii = Scrambler([0, 8, 1, 7, 14, 3, 11, 13, 15, 18, 1, 22, 10, 6, 24, 13, 0, 15, 7, 20, 21, 3, 9, 24, 16, 5], [6])
siii = Scrambler([1, 2, 3, 4, 5, 6, 22, 8, 9, 10, 13, 10, 13, 0, 10, 15, 18, 5, 14, 7, 16, 17, 24, 21, 18, 15], [23])
siv = Scrambler([4, 17, 12, 18, 11, 20, 3, 19, 16, 7, 10, 23, 5, 20, 9, 22, 23, 14, 1, 13, 16, 8, 6, 15, 24, 2], [10])
sv = Scrambler([21, 24, 25, 14, 2, 3, 13, 17, 12, 6, 8, 18, 1, 20, 23, 8, 10, 5, 20, 16, 22, 19, 9, 7, 4, 11], [0])
svi = Scrambler([9, 14, 4, 18, 10, 15, 6, 24, 16, 7, 17, 19, 1, 20, 11, 2, 13, 19, 8, 25, 3, 16, 12, 5, 21, 23],
                [0, 14])
svii = Scrambler([13, 24, 7, 4, 2, 12, 22, 16, 4, 15, 8, 11, 15, 1, 6, 16, 10, 17, 3, 18, 21, 9, 14, 19, 5, 20],
                 [0, 14])
sviii = Scrambler([5, 9, 14, 4, 15, 6, 17, 7, 20, 18, 25, 7, 3, 16, 11, 2, 10, 21, 12, 3, 19, 13, 24, 1, 8, 22],
                  [0, 14])

ra = Reflector([4, 8, 10, 22, 22, 6, 18, 16, 13, 18, 12, 20, 16, 4, 2, 5, 24, 22, 1, 25, 21, 13, 14, 10, 8, 4])
rb = Reflector([24, 16, 18, 4, 12, 13, 5, 22, 7, 14, 3, 21, 2, 23, 24, 19, 14, 10, 13, 6, 8, 1, 25, 12, 2, 20])
rc = Reflector([5, 20, 13, 6, 4, 21, 8, 17, 22, 20, 7, 14, 11, 9, 18, 13, 3, 19, 2, 23, 24, 6, 17, 15, 9, 12])
rbt = Reflector([4, 12, 8, 13, 22, 15, 18, 15, 1, 25, 18, 3, 3, 14, 23, 23, 13, 6, 7, 2, 11, 24, 11, 20, 8, 19])
rct = Reflector([17, 2, 12, 24, 5, 8, 13, 3, 13, 21, 23, 1, 25, 18, 14, 7, 9, 9, 5, 13, 4, 13, 19, 21, 22, 17])

sx = Scrambler([0] * 26)  # some useful blank/minimal ones for testing
rx = Reflector([0] * 26)
rt = Reflector([13] * 26)
px = Plugboard([0] * 26)

possible_scramblers = [si, sii, siii, siv, sv, svi, svii, sviii, sx]
possible_reflectors = [ra, rb, rc, rbt, rct, rx, rt]

# stuff needed for enigmaGUIbasic
main_scrambler_list = [si, sii, siii]
default_machine = Machine(main_scrambler_list,  ra, px)


import tkinter as tk

def ClickedButon():
  name1 = entry1.get()
  name2 = entry2.get()
  love_score = len(set(name1.lower() + name2.lower())) * 10
  result_label.config(text=f"Aşk Skorunuz: {love_score}%")

form = tk.Tk()
form.title('LOVE METER')
form.geometry('400x400+50+100')
form.configure(bg='violet')

label =tk.Label(form,text='LOVE TESTER',fg='blue',bg='purple',font='Times 20 italic bold')
label.pack()

entry1 = tk.Entry(form,bg='purple',show='*')
entry1.pack()

entry2 = tk.Entry(form,bg='purple',show='*')
entry2.pack()

button = tk.Button(form, text="Buton", command=ClickedButon,bg='pink')
button.pack()

result_label = tk.Label(form, text="")
result_label.pack()

label=tk.Label(form,text='Adınızı yazıp butona basın',fg='blue',bg='purple',font='Times 20 italic bold')
label.pack()


from random import choice
from settings import Settings
import pygame

class Moves():
    def __init__(self):
        super().__init__()
        self.laban = {
            "Press":"Images/press.bmp",
            "Flick":"Images/flick.bmp",
            "Wring":"Images/wring.bmp",
            "Dab":"Images/dab.bmp",
            "Slash":"Images/slash.bmp",
            "Glide":"Images/glide.bmp",
            "Thrust":"Images/thrust.bmp",
            "Float":"Images/float.bmp",
        }

        self.transitions = {
            "Spin":"Images/spin.bmp",
            "Step":"Images/step.bmp",
        }

        self.s = Settings()
        self.X = self.s.X//2
        self.Y = self.s.Y//2
        self.pos =  "Centerstage center"

    def get_move(self):
        '''Return a random move'''
        self.rand = choice([0,1])
        if self.rand == 0:
            move = choice(list(self.laban.keys()))
        else:
            move = choice(list(self.transitions.keys()))

        return move

    def update(self,new_img):
        self.image = pygame.image.load(new_img)

    def show_move(self, move):
        if self.rand == 0:
            self.image = pygame.image.load(self.laban[move])
        else:
            self.image = pygame.image.load(self.transitions[move])
        self.image = pygame.transform.scale(self.image,(40,40))
        self.img_rect = self.image.get_rect()
        self.img_rect.center = (self.X,self.Y)
        self.s.screen.blit(self.image,self.img_rect)

    def walk(self):
        if self.rand != 0:
            Xnew = 0
            Ynew = 0
            self.pos = ""
            if self.Y == self.s.Y//6:
                Ynew = choice([0,self.s.Y//3])
                self.pos += "Upstage "
            elif self.Y == self.s.Y//3:
                Ynew = choice([-self.s.Y//3,0,self.s.Y//3])
                self.pos += "Centerstage "
            elif self.Y == self.s.Y//2:
                Ynew = choice([-self.s.Y//3,0])
                self.pos += "Downstage "
            if self.X == self.s.X//6:
                Xnew = choice([0,self.s.X//3])
                self.pos += "left"
            elif self.X == self.s.X//3:
                Xnew = choice([-self.s.X//3,0,self.s.X//3])
                self.pos += "center"
            elif self.X == self.s.X//2:
                Xnew = choice([-self.s.X//3,0])
                self.pos += "right"

            self.X += Xnew
            self.Y += Ynew
            self.s.screen.blit(self.image,self.img_rect)
        return self.pos


# Henrique Sander Lourenço
# 10802705

import gi

gi.require_version("Gtk", "3.0")

from gi.repository import Gtk
from os.path import abspath, dirname, join

# Create App class
class App:

    def __init__(self):

        # Connect to glade file
        self.builder = Gtk.Builder()
        self.builder.add_from_file('converter.glade')

        # Get window object and set title
        self.window = self.builder.get_object('window')
        self.window.set_title('Conversor de unidades')

        # Create quantities and units lists in Gtk
        self.quantities_list = Gtk.ListStore(int, str)
        self.volume_units_list = Gtk.ListStore(int, str)
        self.temperature_units_list = Gtk.ListStore(int, str)

        # Quantities
        quantities = [
            [1, 'Volume'],
            [2, 'Temperatura']]

        # Append quantities to Gtk list
        for qty in quantities:
            self.quantities_list.append(qty)

        # Volume units
        volume_units = [
            [1, 'milímetros cúbicos (mm³)'],
            [2, 'centímetros cúbicos (cm³)'],
            [3, 'litros (L)']]

        # Temperature units
        temperature_units = [
            [1, 'Celsius'],
            [2, 'Farenheint'],
            [3, 'Kelvin']
        ]

        # Append volume units to Gtk list
        for unit in volume_units:
            self.volume_units_list.append(unit)

        # Append temperature units to Gtk list
        for unit in temperature_units:
            self.temperature_units_list.append(unit)

        # Configure combo boxes
        self.combo_qty = self.builder.get_object('combo_qty') # Quantities combo box
        self.combo_from = self.builder.get_object('combo_from') # 'From units' combo box
        self.combo_to = self.builder.get_object('combo_to') # 'To units' combo box
        self.combo_qty.set_model(self.quantities_list) # Set quantities combo box model
        self.combo_from.set_model(self.volume_units_list) # Set 'from units' combo box model
        self.combo_to.set_model(self.volume_units_list) # Set 'to units' combo box model

        # Add combo boxes renderer
        renderer_text = Gtk.CellRendererText()
        self.combo_qty.pack_start(renderer_text, True)
        self.combo_from.pack_start(renderer_text, True)
        self.combo_to.pack_start(renderer_text, True)

        # Choose what to show on combo boxes
        self.combo_qty.add_attribute(renderer_text, "text", 1)
        self.combo_from.add_attribute(renderer_text, "text", 1)
        self.combo_to.add_attribute(renderer_text, "text", 1)

        # Default options
        self.combo_qty.set_active(0)
        self.combo_from.set_active(0)
        self.combo_to.set_active(0)
        self.unitFrom = 1 # Tell which unit the quantity is being converted from
        self.unitTo = 1 # Tell which unit the quantity is being converted to

        # Connect signals
        self.builder.connect_signals(self)

        # Show window
        self.window.show()

        self.quantity = 0 # Tell which quantity is being converted (0 is volume and 1 is temperature)

        self.input = self.builder.get_object('input')
        self.out = self.builder.get_object('output')

    # Close window button
    def on_window_destroy(self, widget):
        Gtk.main_quit()

    # Quantity being converted changed
    def on_qty_changed(self, widget):
        model = widget.get_model()
        active = widget.get_active()
        option = model[active][1] # Get which quantity is selected
        self.input.set_text('')
        # print('Opção selecionada: {}'.format(option)) # Debug only
        if active == 0: # Volume selected
            self.combo_from.set_model(self.volume_units_list)
            self.combo_to.set_model(self.volume_units_list)
            self.combo_from.set_active(0) # Clear 'from units' combo box
            self.combo_to.set_active(0) # Clear 'to units' combo box
            self.quantity = 0
        if active == 1: # Temperature selected
            self.combo_from.set_model(self.temperature_units_list)
            self.combo_to.set_model(self.temperature_units_list)
            self.combo_from.set_active(0) # Clear 'from units' combo box
            self.combo_to.set_active(0) # Clear 'to units' combo box
            self.quantity = 1

    # From unit changed
    def on_from_changed(self, widget):
        model = widget.get_model()
        active = widget.get_active()
        option = model[active][0]
        self.unitFrom = option
        input_text = self.input.get_text()
        self.input.set_text('') # So that on_input_changed is called
        self.input.set_text(input_text)

    # To unit changed
    def on_to_changed(self, widget):
        model = widget.get_model()
        active = widget.get_active()
        option = model[active][0]
        self.unitTo = option
        input_text = self.input.get_text()
        self.input.set_text('') # So that on_input_changed is called
        self.input.set_text(input_text)

    # Input changed
    def on_input_changed(self, widget):
        input = widget.get_text()
        if (input == ''): # Input is empty
            self.out.set_text('')
        if (input.isdigit()): # Input is a number
            # Volume conversion
            if (self.quantity == 0):
                if (self.unitFrom == self.unitTo): # Same units
                    self.out.set_text(input)
                if (self.unitFrom == 1 and self.unitTo == 2): # mm3 to cm3
                    self.out.set_text(str(int(input) / 1000))
                if (self.unitFrom == 1 and self.unitTo == 3): # mm3 to L
                    self.out.set_text(str(int(input) / 1000000))
                if (self.unitFrom == 2 and self.unitTo == 1): # cm3 to mm3
                    self.out.set_text(str(int(input) * 1000))
                if (self.unitFrom == 2 and self.unitTo == 3): # cm3 to L
                    self.out.set_text(str(int(input) / 1000))
                if (self.unitFrom == 3 and self.unitTo == 1): # L to mm3
                    self.out.set_text(str(int(input) * 1000000))
                if (self.unitFrom == 3 and self.unitTo == 2): # L to cm3
                    self.out.set_text(str(int(input) * 1000))
            # Temperature conversion
            if (self.quantity == 1):
                if (self.unitFrom == self.unitTo): # Same units
                    self.out.set_text(input)
                if (self.unitFrom == 1 and self.unitTo == 2): # Celsius to Farenheint
                    self.out.set_text(str(int(input) * 9 / 5 + 32))
                if (self.unitFrom == 1 and self.unitTo == 3): # Celsius to Kelvin
                    self.out.set_text(str(int(input) + 273.15))
                if (self.unitFrom == 2 and self.unitTo == 1): # Farenheint to Celsius
                    self.out.set_text(str((int(input) - 32) * 5 / 9))
                if (self.unitFrom == 2 and self.unitTo == 3): # Farenheint to Kelvin
                    self.out.set_text(str((int(input) - 32) * 5 / 9 + 273.15))
                if (self.unitFrom == 3 and self.unitTo == 1): # Kelvin to Celsius
                    self.out.set_text(str(int(input) - 273.15))
                if (self.unitFrom == 3 and self.unitTo == 2): # Kelvin to Farenheint
                    self.out.set_text(str((int(input) - 273.15) * 9 / 5 + 32))

if __name__ == '__main__':
    try:
        gui = App()
        Gtk.main()
    except KeyboardInterrupt:
        pass


import json

from flask import Blueprint,jsonify,request,abort
from flask_jwt import current_identity, jwt_required
from flask_restful import Resource, Api, reqparse
from sqlalchemy import (func, exc, distinct, inspect, desc)

from appcore.models import db
from appcore.schemas import *
from appcore.common_method import *
from appcore.errors import *

common_resource_bp = Blueprint('common_resource', __name__)
api = Api(common_resource_bp)

class ResourceHandler(Resource):

    @jwt_required()
    def post(self,table_name):
        data = request.get_json(force=True)

        if not validateJson(data, input_schema_dic[table_name]):
            raise BadRequestError("Paramter Error")

        try:
            TableClass = get_class_by_tablename(table_name)
            if TableClass == None: raise Exception("Table not found: %s" % table_name)

            obj = TableClass(**data)
            if "user_id" in TableClass.__table__.columns.keys():
                obj.user_id = current_identity.id

            db.session.add(obj)
            db.session.commit()

            return jsonify({
                "status": "success",
                "id": obj.id,
                })
        except Exception as e:
            db.session.rollback()
            raise BadRequestError(str(e))

    @jwt_required()
    def get(self,table_name):
        try:
            TableClass = get_class_by_tablename(table_name)
            if TableClass == None: raise Exception("Table not found: %s" % table_name)

            query = db.session.query(TableClass)

            if "user_id" in TableClass.__table__.columns.keys():
                query = query.filter_by(user_id = current_identity.id)

            objects = query.all()

            return jsonify({"data":[output_schema_dic[table_name](item) for item in objects]})

        except Exception as e:
            raise BadRequestError(str(e))

class ResourceEditHandler(Resource):

    @jwt_required()
    def delete(self, table_name, id):

        try:
            TableClass = get_class_by_tablename(table_name)
            if TableClass == None:
                raise Exception("Table not found: %s" % table_name)

            query = db.session.query(TableClass)

            obj = query.filter_by(**{"id":id}).first()

            if "is_deleted" in TableClass.__table__.columns.keys():
                setattr(obj,"is_deleted",1)
            else:
                db.session.delete(obj)

            db.session.commit()

            status = {'status': 'success'}
            return jsonify(status)

        except Exception as e:
            db.session.rollback()
            raise BadRequestError(str(e))

    @jwt_required()
    def get(self, table_name, id):

        try:
            TableClass = get_class_by_tablename(table_name)
            if TableClass == None: raise Exception("Table not found: %s" % table_name)

            query = db.session.query(TableClass)

            obj = query.filter_by(**{"id":id}).first_or_404()

            data = output_schema_dic[table_name](obj)

            return jsonify(data)

        except Exception as e:
            raise BadRequestError(str(e))

    @jwt_required()
    def patch(self, table_name, id):

        data = request.get_json(force=True)

        if not validateJson(data, input_schema_dic[table_name]):
            raise BadRequestError("Paramter Error")

        try:
            TableClass = get_class_by_tablename(table_name)
            if TableClass == None: raise Exception("Table not found: %s" % table_name)

            obj = db.session.query(TableClass).filter_by(**{"id":id}).first()

            if obj == None: raise Exception("No data found.")
            for key in data.keys():
                setattr(obj, key, data[key])
            db.session.commit()

            return jsonify({
                "status": "success",
                "id": obj.id,
                })

        except Exception as e:
            db.session.rollback()
            raise BadRequestError(str(e))

class ResourceFetchHandler(Resource):

    @jwt_required()
    def post(self,table_name):

        try:
            TableClass = get_class_by_tablename(table_name)
            if TableClass == None:
                raise Exception("Table not found: %s" % table_name)

            data = request.get_json(force=True)

            query = db.session.query(TableClass)

            if "user_id" in TableClass.__table__.columns.keys():
                query = query.filter_by(user_id = current_identity.id)

            if "is_deleted" in TableClass.__table__.columns.keys():
                query = query.filter_by(is_deleted=False)

            if 'where' in data:
                query = query.filter_by(**data['where'])

            if 'orderby' in data:
                for cname in data['orderby'].split(','):
                    reverse = False
                    if cname.endswith(' desc'):
                        reverse = True
                        cname = cname[:-5]
                    elif cname.endswith(' asc'):
                        cname = cname[:-4]
                    print("cname: ", cname)
                    column = getattr(TableClass, cname)
                    if reverse:
                        column = desc(column)
                    query = query.order_by(column)

            if "inlist" in data:
                for key,val in  data["inlist"].items():
                    query = query.filter(getattr(TableClass, key).in_(val))

            if "like" in data:
                for key,val in  data["like"].items():
                    query = query.filter(getattr(TableClass, key).like("%" + val + "%"))

            if "compare" in data:
                filters = get_filter_by_args(TableClass, data["compare"])
                query = query.filter(*filters)

            if 'limit' in data:
                query = query.limit(data['limit'])

            if 'offset' in data:
                query = query.offset(data['offset'])

            objects = query.all()

            return jsonify({"data":[output_schema_dic[table_name](item) for item in objects]})

        except Exception as e:
            raise BadRequestError(str(e))

api.add_resource(ResourceHandler, '/resource/<table_name>/')

api.add_resource(ResourceEditHandler, '/resource/<table_name>/<int:id>/')

api.add_resource(ResourceFetchHandler, '/resource/<table_name>/fetch/')


import pdb
from collections import defaultdict

def print_sentence(srcid):
    self.sentence_dict[srcid]
from collections import OrderedDict
import json
import random
from functools import reduce

def adder(x, y):
    return x + y

def splitter(s):
    return s.split()

class BaseScrabble(object):
    """docstring for BaseScrabble"""
    def __init__(self,
                 target_building,
                 target_srcids,
                 building_label_dict,
                 building_sentence_dict,
                 building_tagsets_dict,
                 source_buildings=[],
                 source_sample_num_list=[],
                 learning_srcids=[],
                 config={}):
        self.source_buildings = source_buildings
        self.target_building = target_building
        if self.target_building not in self.source_buildings:
            self.source_buildings.append(self.target_building)
            self.source_sample_num_list.append(0)
        self.source_sample_num_list = source_sample_num_list
        self.building_tagsets_dict = building_tagsets_dict
        self.use_brick_flag = False  # Temporarily disable it
        self.building_sentence_dict = building_sentence_dict
        self.building_label_dict = building_label_dict
        self.target_srcids = target_srcids
        self.learning_srcids = learning_srcids
        self.config = config
        self.history = []

    def sub_dict_by_key_set(self, d, ks):
        return dict((k,v) for k, v in d.items() if k in ks)

    def leave_one_word(self, s, w):
        if w in s:
            s = s.replace(w, '')
            s = w + '-' + s
        return s

    def find_keys(self, tv, d, crit=lambda x,y:x==y):
        keys = list()
        for k, v in d.items():
            if crit(tv, v):
                keys.append(k)
        return keys

    def check_in(self, x, y):
        return x in y

    def select_random_samples_dep(
            self,
            building,
            srcids,
            n,
            use_cluster_flag,
            token_type='justseparate',
            reverse=True,
            cluster_dict=None,
            shuffle_flag=True,
            ):
        if not cluster_dict:
            cluster_filename = 'model/%s_word_clustering_%s.json' % (building, token_type)
            with open(cluster_filename, 'r') as fp:
                cluster_dict = json.load(fp)

        # Learning Sample Selection
        sample_srcids = set()
        length_counter = lambda x: len(x[1])
        ander = lambda x, y: x and y
        if use_cluster_flag:
            sample_cnt = 0
            sorted_cluster_dict = OrderedDict(
                sorted(cluster_dict.items(), key=length_counter, reverse=reverse))
            #n = len(sorted_cluster_dict) #TODO: Remove if not working well
            while len(sample_srcids) < n:
                cluster_dict_items = list(sorted_cluster_dict.items())
                if shuffle_flag:
                    random.shuffle(cluster_dict_items)
                for cluster_num, srcid_list in cluster_dict_items:
                    valid_srcid_list = set(srcid_list)\
                            .intersection(set(srcids))\
                            .difference(set(sample_srcids))
                    if len(valid_srcid_list) > 0:
                        sample_srcids.add(\
                                random.choice(list(valid_srcid_list)))
                    if len(sample_srcids) >= n:
                        break
        else:
            sample_srcids = random.sample(srcids, n)
        return list(sample_srcids)

    def alpha_tokenizer(s):
        return re.findall('[a-zA-Z]+', s)

    def adder(x, y):
        return x+y

    def hier_clustering(d, threshold=3):
        srcids = d.keys()
        tokenizer = lambda x: x.split()
        vectorizer = TfidfVectorizer(tokenizer=tokenizer)
        assert isinstance(d, dict)
        assert isinstance(list(d.values())[0], list)
        assert isinstance(list(d.values())[0][0], str)
        doc = [' '.join(d[srcid]) for srcid in srcids]
        vect = vectorizer.fit_transform(doc)
        #TODO: Make vect aligned to the required format
        z = linkage(vect.toarray(), metric='cityblock', method='complete')
        dists = list(set(z[:,2]))
#    threshold = 3
        #threshold = (dists[2] + dists[3]) / 2
        b = hier.fcluster(z, threshold, criterion='distance')
        cluster_dict = defaultdict(list)
        for srcid, cluster_id in zip(srcids, b):
            cluster_dict[str(cluster_id)].append(srcid)
        value_lengther = lambda x: len(x[1])
        return OrderedDict(\
                   sorted(cluster_dict.items(), key=value_lengther, reverse=True))

    def set_logger(logfile=None):
        logger = logging.getLogger()
        logger.setLevel(logging.DEBUG)
        formatter = logging.Formatter('%(asctime)s %(message)s')

        # Console Handler
        ch = logging.StreamHandler(stream=sys.stdout)
        ch.setFormatter(formatter)
        ch.setLevel(logging.DEBUG)
        logger.addHandler(ch)

        # File Handler
        if logfile:
            fh = logging.FileHandler(logfile, mode='w+')
            fh.setFormatter(formatter)
            fh.setLevel(logging.DEBUG)
            logger.addHandler(fh)
        return logger

    def parallel_func(orig_func, return_idx, return_dict, *args):
        return_dict[return_idx] = orig_func(*args)

    def iteration_wrapper(self, iter_num, func, prev_data=None, *params):
        step_datas = list()
        if not prev_data:
            prev_data = {'iter_num':0,
                         'learning_srcids': [],
                         'model_uuid': None}
        for i in range(0, iter_num):
            print('{0} th stage started'.format(prev_data['iter_num']))
            step_data = func(prev_data, *params)
            print('{0} th stage finished'.format(prev_data['iter_num']))
            step_datas.append(step_data)
            prev_data = step_data
            prev_data['iter_num'] += 1
        return step_datas

    def replace_num_or_special(word):
        if re.match('\d+', word):
            return 'NUMBER'
        elif re.match('[a-zA-Z]+', word):
            return word
        else:
            return 'SPECIAL'

    def adder(x, y):
        return x + y

    def get_random_srcids_dep(self,
                          building_srcid_dict,
                          building_list,
                          source_sample_num_list):
        srcids = list()
        for building, source_sample_num in zip(building_list,
                                               source_sample_num_list):
                                            #  Load raw sentences of a building
            sentence_dict = self.building_sentence_dict[building]

            # Select learning samples.
            # Learning samples can be chosen from the previous stage.
            # Or randomly selected.
            sample_srcid_list = self.select_random_samples_dep(
                building,
                #label_dict.keys(),
                self.building_srcid_dict[building],
                source_sample_num,
                use_cluster_flag=True)
            srcids += sample_srcid_list
        return srcids

    def get_cluster_dict(building):
        cluster_filename = 'model/%s_word_clustering_justseparate.json' % \
                               (building)
        with open(cluster_filename, 'r') as fp:
            cluster_dict = json.load(fp)
        return cluster_dict

    def get_label_dict(building):
        filename = 'metadata/%s_label_dict_justseparate.json' % \
                               (building)
        with open(filename, 'r') as fp:
            data = json.load(fp)
        return data

    def print_sentence(self, srcid):
        print(''.join(self.sentence_dict[srcid]))

    def print_pred(self, preds, srcids):
        for srcid in srcids:
            sentence = self.sentence_dict[srcid]
            char_labels = self.label_dict[srcid]
            for char_label, char_pred, char \
                    in zip(char_labels, preds[srcid], sentence):
                is_correct = char_label == char_pred
                print('{0}: {1}\t{2}\t{3}'.format('O' if is_correct else 'X',
                                                  char_pred, char_label, char))

    def get_learning_sample_nums(self):
        num_samples = defaultdict(int)
        for srcid in self.learning_srcids:
            for building, sentences in self.building_sentence_dict.items():
                if srcid in sentences:
                    num_samples[building] += 1
                    break
        assert sum(num_samples.values()) == len(set(self.learning_srcids))
        return num_samples


from Entity import *

class Category(Entity):
   _fields   = ['title']
   _parents  = []
   _children = ['article']
   _siblings = []

class Article(Entity):
   _fields   = ['text', 'title']
   _parents  = ['category']
   _children = []
   _siblings = ['tag']

class Tag(Entity):
   _fields   = ['value']
   _parents  = []
   _children = []
   _siblings = ['article']


#!/usr/bin/python

import os
import numpy as np

rootdir  = '/media/data/oasis_aal'

#create a txt file combining both aal files
aal1f = rootdir + os.path.sep + 'aal.txt'
aal2f = rootdir + os.path.sep + 'aal.nii.txt'
aal3f = rootdir + os.path.sep + 'aal_allvalues.txt'

aal1 = np.loadtxt(aal1f, dtype=str)
aal2 = np.loadtxt(aal2f, dtype=str)

m = aal1.shape[0]
n = aal1.shape[1]

aal  = np.zeros((m,n+1), dtype=aal1.dtype)

aal[:,0:3] = aal1
aal[:,3] = aal2[:,0]

np.savetxt (aal3f, aal, fmt='%s')


import hashlib
import json
import os
import time
import tldextract
import concurrent.futures

# File paths
blacklist_path = "data/blacklist.txt"
blockchain_data_path = "data/blockchain_data.json"

# Maximum number of transactions to keep in the blockchain
max_transactions = 100000000

import tldextract

def is_valid_fqdn(fqdn):
    # Use tldextract to parse the FQDN
    extracted = tldextract.extract(fqdn)

    # Check if a domain is present and meets validation criteria
    if not extracted.domain:
        return False

    # Check if a TLD is present and meets validation criteria
    if not extracted.suffix:
        return False

    # Additional checks for the domain and TLD format
    # For example, you can check if the domain contains only alphanumeric characters and hyphens
    # You can also check if the TLD is at least 2 characters long
    if not extracted.domain.isalnum() or '-' in extracted.domain:
        return False
    if len(extracted.suffix) < 2:
        return False

    # If all checks pass, consider the FQDN valid
    return True

# Function to calculate hash for a transaction
def calculate_hash(transaction):
    transaction_str = json.dumps(transaction, sort_keys=True)
    return hashlib.sha256(transaction_str.encode()).hexdigest()

# Function to process a batch of rows and create transactions
def process_batch(batch_lines):
    transactions = []

    for line in batch_lines:
        line = line.strip()
        # Skip comments and empty lines
        if line.startswith("#") or not line:
            continue

        # Check if the line is a valid FQDN (you can add more validation here)
        if is_valid_fqdn(line):
            # Create a transaction
            transaction = {
                "fqdn": line,
                "timestamp": str(time.time()),  # Use current timestamp
                "previous_hash": "",  # Will be filled later when added to the blockchain
            }
            # Calculate hash for the current transaction
            transaction["hash"] = calculate_hash(transaction)
            # Generate a serial value
            transactions.append(transaction)

    return transactions

# Function to save transactions to the blockchain data file
def save_transactions_to_blockchain(transactions):
    blockchain_data = []

    try:
        # Load existing blockchain data if available
        if os.path.exists(blockchain_data_path):
            with open(blockchain_data_path, "r") as blockchain_file:
                blockchain_data = json.load(blockchain_file)

        # Append new transactions to the existing data
        blockchain_data.extend(transactions)

        # Prune old transactions if the maximum limit is exceeded
        if len(blockchain_data) > max_transactions:
            blockchain_data = blockchain_data[-max_transactions:]

        # Save the updated blockchain data
        with open(blockchain_data_path, "w") as blockchain_file:
            json.dump(blockchain_data, blockchain_file, indent=4)

    except FileNotFoundError:
        # If the data file doesn't exist, create it with the new transactions
        with open(blockchain_data_path, "w") as blockchain_file:
            json.dump(transactions, blockchain_file, indent=4)

if __name__ == "__main__":
    try:
        # Check if the script should run based on a defined interval (e.g., every 2 hours)
        current_time = time.time()
        interval_seconds = 2 * 60 * 60  # 2 hours in seconds
        last_run_time_path = "data/last_run_time.txt"

        if os.path.exists(last_run_time_path):
            with open(last_run_time_path, "r") as last_run_time_file:
                last_run_time = float(last_run_time_file.read())
                if current_time - last_run_time < interval_seconds:
                    print("Script already ran within the specified interval. Exiting.")
                    exit(0)

        # Read the blacklist file
        with open(blacklist_path, "r") as blacklist_file:
            lines = blacklist_file.readlines()

        print("Processing the blacklist...")
        total_lines = len(lines)
        batch_size = 10000000
        start = 0

        # Process batches concurrently
        with concurrent.futures.ThreadPoolExecutor() as executor:
            while start < total_lines:
                end = min(start + batch_size, total_lines)
                batch_lines = lines[start:end]

                # Process the batch and get transactions
                transactions = process_batch(batch_lines)

                if transactions:
                    # Save the transactions to the blockchain data file
                    if os.path.exists(blockchain_data_path):
                        print(f"Appending {len(transactions)} transactions to the blockchain.")
                    else:
                        print(f"Creating a new blockchain with {len(transactions)} transactions.")

                    save_transactions_to_blockchain(transactions)

                start = end

                # Print progress
                processed_lines = start
                progress_percent = (processed_lines / total_lines) * 100
                print(f"Progress: {processed_lines}/{total_lines} lines processed ({progress_percent:.2f}%)")

        # Update the last run time
        with open(last_run_time_path, "w") as last_run_time_file:
            last_run_time_file.write(str(current_time))

        print(f"Processing completed. {len(transactions)} valid transactions created and saved.")

    except Exception as e:
        print(f"An error occurred: {str(e)}")


'''
Given a list of numbers L, implement a method sum(i, j) which returns the sum from the sublist L[i:j] (including i, excluding j).

For example, given L = [1, 2, 3, 4, 5], sum(1, 3) should return sum([2, 3]), which is 5.

You can assume that you can do some pre-processing. sum() should be optimized over the pre-processing step.
'''

from typing import List

class ListSumOptimizer:
    def __init__(self, num_arr: List[int]):
        self._num_arr = num_arr
        self._sum_arr = []
        self._calculate_sum()

    # Preprocess method. Creates a list of sums of all previous numbers prior to its index.
    def _calculate_sum(self):
        self._sum_arr = [0]
        for i, num in enumerate(self._num_arr):
            self._sum_arr.append(num + self._sum_arr[i])
        return

    # Set the num_arr to a property so that when it's modified, we can automatically recalculate _sum_arr.
    @property
    def num_arr(self):
        return self._num_arr

    @num_arr.setter
    def num_arr(self, num_arr: List[int]):
        self._num_arr = num_arr
        self._calculate_sum()
        return

    # Sum method. Due to preprocessing, we can do a single subtraction operation to get the sum from i to j instead of a loop.
    def sum(self, i: int, j: int):
        if i > j:
            raise ValueError("Start index must be less than or equal to the end index.")
        if i < 0 or j > len(self._num_arr):
            raise IndexError("Start index and/or end index out of range.")

        return self._sum_arr[j] - self._sum_arr[i]

x = ListSumOptimizer([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(x.sum(3, 7)) # 22
print(x.sum(0, 10)) # 55
x.num_arr = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
print(x.sum(3, 7)) # 62


def histogram(s):
    d = dict()
    for c in s:
        d[c] = d.get(c,0)
        d[c] = d[c]+ 1
    return d

def print_hist(h):
    for c in sorted(h):
        print(c,h[c])

h = histogram('AAAbrontosaurusxxxxxxx')
#print_hist(h)

print(h)


import numpy as np
import os
import math
import itertools

eps=1e-8
niter=10

def normalize_POVM(M):
    M_sum=np.sum(M,axis=(0))
    try:
        M_normalizer=np.linalg.inv(np.linalg.cholesky(M_sum))
    except np.linalg.LinAlgError:
        print('trying to normalize a matrix that is not positive definite')
        return None
    return M_normalizer@M@(M_normalizer.transpose().conjugate())

def POVM_operator_to_element(E):
    return E@(E.conjugate().transpose((0,2,1)))

def sanitize_POVM(x):
    M=x[0,:,:,:,:,:]+1.0j*x[1,:,:,:,:,:]
    n,m,k,d,_=M.shape
    for i in range(n):
        for j in range(m):
            M[i,j]=normalize_POVM(POVM_operator_to_element(M[i,j]))
    return M,n,m,k,d

def iterate_correlation(M):
    n,m,k,d,_=M.shape
    for tx in range(m):
        for ty in range(m):
            for ta in range(k):
                for tb in range(k):
                    yield (tx,ty),(ta,tb),np.kron(M[0,tx,ta],M[1,ty,tb])

def generate_correlation(x,state):
    M,n,m,k,d=sanitize_POVM(x)
    corr_shape=tuple([m]*n+[k]*n)
    corr=np.zeros(corr_shape)
    for tx,ta,tO in iterate_correlation(M):
        corr[tuple(list(tx)+list(ta))]=np.sum(state.conjugate()*tO).real
    return corr

def generate_Bell_operator(x,bf,engine=None):
    M,n,m,k,d=sanitize_POVM(x)
    if engine!=None:
        return engine(M,bf)
    BO=np.zeros((d**n,d**n)).astype(np.complex128)
    for tx,ta,tO in iterate_correlation(M):
        BO+=bf[tuple(list(tx)+list(ta))]*tO
    return BO

n,m,k,d=2,2,3,3
bf=np.loadtxt('corr_functional').reshape((2,2,k,k))
optx=np.zeros((2,2,m,k,d,d))
MA=np.zeros((m,k,d,d)).astype(np.complex128)
MB=np.zeros((m,k,d,d)).astype(np.complex128)
for s in range(m):
    for t1 in range(d):
        vecA=np.zeros((d,1)).astype(np.complex128)
        vecB=np.zeros((d,1)).astype(np.complex128)
        pA=s/m
        pB=(0.5-s)/m
        for t2 in range(d):
            vecA[t2,0]=np.exp(1.0j*2.0*math.pi/d*t2*(t1+pA))
            vecB[t2,0]=np.exp(1.0j*2.0*math.pi/d*t2*(-t1+pB))
        vecA/=np.sum(vecA*(vecA.conjugate()))**0.5
        vecB/=np.sum(vecB*(vecB.conjugate()))**0.5
        MA[s,t1]=vecA@(vecA.transpose().conjugate())
        MB[s,t1]=vecB@(vecB.transpose().conjugate())
optx[0,0,:,:,:,:]=MA.real
optx[1,0,:,:,:,:]=MA.imag
optx[0,1,:,:,:,:]=MB.real
optx[1,1,:,:,:,:]=MB.imag

BO=generate_Bell_operator(optx,bf)
v,w=np.linalg.eig(BO)
ind=np.argmax(v.real)
base_state=w[:,ind].reshape((-1,1))

for eps_state in np.logspace(-1,-3,niter):
    tmp_state=base_state+np.random.normal(0,eps_state,base_state.shape)+1.0j*np.random.normal(0,eps_state,base_state.shape)
    tmp_state/=np.sum(tmp_state*(tmp_state.conjugate()))**0.5
    tmp_state=tmp_state.reshape(-1,1)@(tmp_state.reshape(1,-1).conjugate())
    corr=generate_correlation(optx,tmp_state)
    np.savetxt('corr',corr.reshape(-1))
    os.system('./bound')


import vk_api
import pyfiglet
from colorama import init, Fore, Back, Style
import random
import time
import os
import sys

banner = """

██╗░░░██╗██╗░░██╗░█████╗░░█████╗░███╗░░░███╗███╗░░░███╗
██║░░░██║██║░██╔╝██╔══██╗██╔══██╗████╗░████║████╗░████║
╚██╗░██╔╝█████═╝░██║░░╚═╝██║░░██║██╔████╔██║██╔████╔██║
░╚████╔╝░██╔═██╗░██║░░██╗██║░░██║██║╚██╔╝██║██║╚██╔╝██║
░░╚██╔╝░░██║░╚██╗╚█████╔╝╚█████╔╝██║░╚═╝░██║██║░╚═╝░██║
░░░╚═╝░░░╚═╝░░╚═╝░╚════╝░░╚════╝░╚═╝░░░░░╚═╝╚═╝░░░░░╚═╝
"""

subscribe = """
Подписаться на автора в Telegram? (yes/no)
"""
print(Fore.CYAN + banner)
print(Fore.CYAN + subscribe)

choose = input('--> ')

if choose == "yes":
    os.system("termux-open-url 'https://t.me/TerPackZ'")
    print("Если вы подписались, перезапустите скрипт :)")
    exit()
else:

    token = input("Введите токен: ")
    user_id = input("Введите айди страницы: ")
    posts_id = input("Введите айди поста: ")
    msgs = input("Введите сообщение: ")
    vk_session = vk_api.VkApi(token=token)
    vk = vk_session.get_api()
    apivk = vk.API(vk_session, v=5.95)
while True:
    try:
        print(apivk.wall.createComment(owner_id=user_id, post_id=posts_id, message=msgs,
                                       guid=random.randint(0, 9999999999)))
    except:
        pass
    time.sleep(3)


import unittest
from problem29 import lengthDistinctPowerSequence

class MyTestcase(unittest.TestCase):
    def test_lengthDistinctPowerSequence(self):
        testData = {
            15: 177,
            20: 324,
            25: 519,
            30: 755,
        }
        for key in testData:
            self.assertEqual(testData[key], lengthDistinctPowerSequence(key))

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


import sys
sys.setrecursionlimit(10**6)
read = sys.stdin.readline

A,B = map(int,read().split())
r = [ [] for _ in range(A+1) ]
ch = [0]*(A+1)

for _ in range(B):
    x,y = map(int,read().split())
    r[x].append(y)
    r[y].append(x)

# 시작점이 정해졌을때에, DFS
def DFS(i):
    ch[i] = 1
    for j in r[i]:
        if ch[j] == 0 :
            DFS(j)
cnt = 0
for i in range(1,A+1):
    if ch[i] == 0 :
        cnt += 1
        DFS(i)
print(cnt)