# -*- coding: utf-8 -*-
"""
:synopsis: views "read-only" for main textual content

By main textual content is meant - text of Questions, Answers and Comments.
The "read-only" requirement here is not 100% strict, as for example "question" view does
allow adding new comments via Ajax form post.
"""

import datetime
import operator
import re
# import os

from django import forms
from django.conf import settings
from django.db.models import Q
from django.views.decorators import csrf
from django.core.exceptions import ObjectDoesNotExist
from django.core.paginator import Paginator, EmptyPage
from django.core.urlresolvers import reverse
from django.contrib.humanize.templatetags import humanize
from django.contrib.auth.models import User
from django.http import (
    HttpResponseRedirect,
    HttpResponse,
    Http404,
    HttpResponseNotAllowed,
    QueryDict,
    )
from django.shortcuts import get_object_or_404
# from django.template import Context
from django.utils import simplejson, translation
# from django.utils.html import escape
from django.utils.translation import ugettext as _, ungettext
from django_select2 import AutoSelect2MultipleField, AutoHeavySelect2MultipleWidget
from django_select2.util import JSFunction
# from django_select2 import Select2MultipleChoiceField
# from jinja2 import Environment, FileSystemLoader

from openode import conf, const, models, schedules
from openode.conf import settings as openode_settings
from openode.document.forms import DownloadZipForm
from openode.models import StaticPage
from openode.models.actuality import Actuality
from openode.models.node import Node
from openode.models.post import Post
from openode.models.tag import Tag
from openode.models.thread import ThreadCategory, Thread
from openode.utils import JsonResponse
# from openode.utils import functions
from openode.utils.decorators import anonymous_forbidden, ajax_only, get_only
from openode.utils.diff import textDiff as htmldiff
from openode.utils.html import bleach_html
from openode.utils.http import render_forbidden
from openode.utils.text import extract_numbers
from openode.views.node import node_ask_to_join
from openode.search.state_manager import SearchState
from openode.skins.loaders import render_into_skin, get_template  # jinja2 template loading enviroment
from openode.templatetags import extra_tags
from openode.views.live import get_live_data, check_perm, PER_PAGE as LIVE_PER_PAGE
# from openode.views.thread import thread as thread_detail_view

#######################################

# used in index page
#TODO: - take these out of const or settings

INDEX_PAGE_SIZE = 30
INDEX_TAGS_SIZE = 25
# used in tags list
DEFAULT_PAGE_SIZE = 60
# used in questions
# used in answers

OPENED_NODES_KEY = "opened_nodes___"
OPENED_CATEGORIES_KEY = "opened_categories___"
DISPLAY_MODE_KEY = "display_mode"

DISPLAY_MODE_ACTIVE = 1
DISPLAY_MODE_ACTIVE_AND_CLOSED = 2
# DISPLAY_MODES = {
#     1: DISPLAY_MODE_ACTIVE,
#     2: DISPLAY_MODE_ACTIVE_AND_CLOSED,
# }

#######################################

class NodeUserAutoHeavySelect2MultipleWidget(AutoHeavySelect2MultipleWidget):
    def __init__(self, *args, **kwargs):
        super(AutoHeavySelect2MultipleWidget, self).__init__(*args, **kwargs)
        self.options['initSelection'] = JSFunction("load_selected")

class NodeUserPublicChoices(AutoSelect2MultipleField):
    widget = NodeUserAutoHeavySelect2MultipleWidget

    def get_results(self, request, term, page, context):
        qs = User.objects.filter(
            is_active=True,
            is_hidden=False
        )

        for part in term.split(" "):
            qs = qs.filter(
                Q(
                    Q(display_name__istartswith=part)
                    | Q(last_name__istartswith=part)
                    | Q(first_name__istartswith=part)
                    | Q(email__istartswith=part)
                )
            )

        qs = qs.only(
            "display_name",
            "first_name",
            "last_name",
            "id"
        )

        return (
            "nil",  # errors
            False,  # is paginated
            [(u.id, u.screen_name) for u in qs]
        )

    def label_from_instance(self, obj):
        return obj.screen_name

class SearchUserForm(forms.Form):
    authors = NodeUserPublicChoices(label=_("Authors"))

#######################################

#refactor? - we have these
#views that generate a listing of questions in one way or another:
#index, unanswered, questions, search, tag
#should we dry them up?
#related topics - information drill-down, search refinement

# from openode.search.state_manager import SearchState

def index(request):  # generates front page - shows listing of questions sorted in various ways
    """index view mapped to the root url of the site
    """
    # actuality
    try:
        latest_actuality = Actuality.objects.latest("created")
    except Actuality.DoesNotExist:
        latest_actuality = None

    contributors = User.objects.filter(
        is_active=True, is_hidden=False,
        id__in=Post.objects.values_list('author', flat=True)
    ).order_by('avatar_type', '?')[:12] #todo to live settings

    tags = Tag.objects.filter(
        used_count__gte=1
    )[:10]

    # set and store display mode
    _mode = request.session.setdefault(DISPLAY_MODE_KEY, None)
    try:
        dm = int(request.GET.get("dm"))
    except (TypeError, ValueError):
        dm = _mode or DISPLAY_MODE_ACTIVE
    if dm in [DISPLAY_MODE_ACTIVE, DISPLAY_MODE_ACTIVE_AND_CLOSED]:
        mode = dm
    else:
        mode = DISPLAY_MODE_ACTIVE
    if _mode != mode:
        request.session[DISPLAY_MODE_KEY] = mode

    # filter nodes
    root_nodes_qs = Node.objects.filter(level=0, deleted=False)
    if mode == DISPLAY_MODE_ACTIVE:
        with_closed = False
        root_nodes_qs = root_nodes_qs.filter(closed=with_closed)
    else:
        with_closed = True

    # load opened nodes from session
    opened_nodes = list(
        request.session.setdefault(
            OPENED_NODES_KEY,
            set(Node.objects.filter(display_opened=True).values_list("pk", flat=True))
        )
    )

    context_dict = {
        # 'node_items': Node.objects.filter(level=0),
        "nodes": root_nodes_qs,
        "with_closed": with_closed,
        "display_mode": mode,

        "latest_actuality": latest_actuality,
        "opened_nodes": simplejson.dumps(opened_nodes),

        "contributors": contributors,

        "DISPLAY_MODE_ACTIVE": DISPLAY_MODE_ACTIVE,
        "DISPLAY_MODE_ACTIVE_AND_CLOSED": DISPLAY_MODE_ACTIVE_AND_CLOSED,

        "tags": tags,
        "tag_html_tag": "li",
        "tag_list_type": "list"
    }
    return render_into_skin('homepage.html', context_dict, request)

#######################################
#######################################

def toggle_node(request):
    """
        close / open node tree and store this information to session
    """
    try:
        node_id = int(request.GET.get("node_id"))
    except (ValueError, TypeError):
        node_id = None

    opened_nodes = set(request.session.setdefault(OPENED_NODES_KEY, []))

    try:
        _node = Node.objects.get(pk=node_id)
    except Node.DoesNotExist:
        _node = None

    if node_id:
        if node_id in opened_nodes:
            # close sub node
            if _node:
                opened_nodes.difference_update(_node.get_descendants().values_list("id", flat=True))
            # close node
            opened_nodes.remove(node_id)

        # open node
        elif (_node.parent_id in opened_nodes) or (_node.level == 0):
            opened_nodes.add(node_id)

        request.session[OPENED_NODES_KEY] = opened_nodes

    return JsonResponse({})

def toggle_category(request):
    """
        close / open category tree and store this information to session
    """
    try:
        category_id = int(request.GET.get("category_id"))
    except (ValueError, TypeError):
        category_id = None

    opened_categories = set(request.session.setdefault(OPENED_CATEGORIES_KEY, []))

    try:
        _category = ThreadCategory.objects.get(pk=category_id)
    except ThreadCategory.DoesNotExist:
        _category = None

    if category_id:
        if category_id in opened_categories:
            # close sub category
            if _category:
                opened_categories.difference_update(_category.get_descendants().values_list("id", flat=True))
            # close category
            opened_categories.remove(category_id)

        # open category
        elif (_category.parent_id in opened_categories) or (_category.level == 0):
            opened_categories.add(category_id)

        request.session[OPENED_CATEGORIES_KEY] = opened_categories

    return JsonResponse({})

#######################################
#######################################

def static_page(request, slug):
    """
        static page detail page
    """
    static_page = get_object_or_404(
        StaticPage,
        slug=slug,
        language=request.LANGUAGE_CODE
    )
    to_tmpl = {
        "static_page": static_page
    }
    return render_into_skin('cms/static_page.html', to_tmpl, request)

def archive(request):
    """
        archive of Actualities
    """
    PER_PAGE = 3

    actualities = Actuality.objects.all().order_by("created")
    paginator = Paginator(actualities, PER_PAGE)

    page = request.GET.get('page')
    try:
        actualities = paginator.page(page)
    except TypeError:
        actualities = paginator.page(1)
    except EmptyPage:
        actualities = paginator.page(paginator.num_pages)

    to_tmpl = {
        "actualities": actualities,
        "paginator": paginator
    }
    return render_into_skin("cms/archive.html", to_tmpl, request)

NODE_MODULE_TEMPLATE_FILE = {
    const.NODE_MODULE_ANNOTATION: 'node/annotation/show.html',
    const.NODE_MODULE_QA: 'node/question/list.html',
    const.NODE_MODULE_FORUM: 'node/discussion/list.html',
    const.NODE_MODULE_LIBRARY: 'node/document/list.html',
}

def node_module_thread(request, node, module, **kwargs):

    redirect = False
    search_user_form = SearchUserForm(request.GET)
    if search_user_form.is_valid():
        ids = [
            int(_id) for _id in
            extract_numbers(search_user_form.data["authors"])
        ]
        kwargs.update({"author": ids})
        redirect = True

    search_state = SearchState(
        user_logged_in=request.user.is_authenticated(),
        node=node,
        module=module,
        request=request,
        **kwargs
        )

    if redirect:
        return HttpResponseRedirect(search_state.full_url())

    if search_state.author:
        search_user_form.data["authors"] = extract_numbers(search_state.author)

    page_size = int(openode_settings.DEFAULT_QUESTIONS_PAGE_SIZE)

    qs, meta_data = models.Thread.objects.run_advanced_search(
        request_user=request.user,
        search_state=search_state
        )
    if meta_data['non_existing_tags']:
        search_state = search_state.remove_tags(meta_data['non_existing_tags'])

    paginator = Paginator(qs, page_size)
    if paginator.num_pages < search_state.page:
        search_state.page = 1
    page = paginator.page(search_state.page)
    page.object_list = list(page.object_list)  # evaluate the queryset

    # INFO: Because for the time being we need question posts and thread authors
    #       down the pipeline, we have to precache them in thread objects

    models.Thread.objects.precache_view_data_hack(threads=page.object_list)

    related_tags = Tag.objects.get_related_to_search(
        threads=page.object_list,
        ignored_tag_names=meta_data.get('ignored_tag_names', [])
    )
    tag_list_type = openode_settings.TAG_LIST_FORMAT
    if tag_list_type == 'cloud':  # force cloud to sort by name
        related_tags = sorted(related_tags, key=operator.attrgetter('name'))

    contributors = list(
        models.Thread.objects.get_thread_contributors(
            thread_list=page.object_list
        ).only('id', 'username', 'gravatar')
    )

    paginator_context = {
        'is_paginated': (paginator.count > page_size),

        'pages': paginator.num_pages,
        'page': search_state.page,
        'has_previous': page.has_previous(),
        'has_next': page.has_next(),
        'previous': page.previous_page_number(),
        'next': page.next_page_number(),

        'base_url': search_state.query_string(),
        'page_size': page_size,
    }

    # We need to pass the rss feed url based
    # on the search state to the template.
    # We use QueryDict to get a querystring
    # from dicts and arrays. Much cleaner
    # than parsing and string formating.
    rss_query_dict = QueryDict("").copy()
    if search_state.query:
        # We have search string in session - pass it to
        # the QueryDict
        rss_query_dict.update({"q": search_state.query})
    if search_state.tags:
        # We have tags in session - pass it to the
        # QueryDict but as a list - we want tags+
        rss_query_dict.setlist("tags", search_state.tags)

    reset_method_count = len(filter(None, [search_state.query, search_state.tags, meta_data.get('author_name', None)]))

    if request.is_ajax():
        # q_count = paginator.count

        # question_counter = ungettext('%(q_num)s question', '%(q_num)s questions', q_count)
        # question_counter = question_counter % {'q_num': humanize.intcomma(q_count)}

        # if q_count > page_size:
        #     paginator_tpl = get_template('node/paginator.html', request)
        #     paginator_html = paginator_tpl.render(Context({
        #         'context': functions.setup_paginator(paginator_context),
        #         'questions_count': q_count,
        #         'page_size': page_size,
        #         'search_state': search_state,
        #     }))
        # else:
        #     paginator_html = ''

        # questions_tpl = get_template('node/questions_loop.html', request)
        # questions_html = questions_tpl.render(Context({
        #     'threads': page,
        #     'search_state': search_state,
        #     'reset_method_count': reset_method_count,
        #     'request': request
        # }))

        # ajax_data = {
        #     'query_data': {
        #         'tags': search_state.tags,
        #         'sort_order': search_state.sort,
        #         'ask_query_string': search_state.ask_query_string(),
        #     },
        #     'paginator': paginator_html,
        #     'question_counter': question_counter,
        #     'faces': [],  # [extra_tags.gravatar(contributor, 48) for contributor in contributors],
        #     'query_string': search_state.query_string(),
        #     'page_size': page_size,
        #     'questions': questions_html.replace('\n', ''),
        #     'non_existing_tags': meta_data['non_existing_tags']
        # }
        # ajax_data['related_tags'] = [{
        #     'name': escape(tag.name),
        #     'used_count': humanize.intcomma(tag.local_used_count)
        # } for tag in related_tags]

        ajax_data = {"msg": "bad request"}
        node.visit(request.user)
        return HttpResponse(simplejson.dumps(ajax_data), mimetype='application/json')

    else:  # non-AJAX branch

        template_data = {
            # ThreadCategory Tree root
            "categories": node.thread_categories.filter(level=0),
            "search_user_form": search_user_form,
            'active_tab': 'questions',
            'authors': meta_data.get('authors', []),
            'contributors': contributors,
            'context': paginator_context,
            'is_unanswered': False,  # remove this from template
            'interesting_tag_names': meta_data.get('interesting_tag_names', None),
            'ignored_tag_names': meta_data.get('ignored_tag_names', None),
            'subscribed_tag_names': meta_data.get('subscribed_tag_names', None),
            'language_code': translation.get_language(),
            'name_of_anonymous_user': models.get_name_of_anonymous_user(),
            'page_class': 'main-page',
            'page_size': page_size,
            'threads': page,
            'questions_count': paginator.count,
            'reset_method_count': reset_method_count,
            'tags': related_tags,
            'tag_list_type': tag_list_type,
            'font_size': extra_tags.get_tag_font_size(related_tags),
            'display_tag_filter_strategy_choices': conf.get_tag_display_filter_strategy_choices(),
            'email_tag_filter_strategy_choices': const.TAG_EMAIL_FILTER_STRATEGY_CHOICES,
            'update_avatar_data': schedules.should_update_avatar_data(request),
            'search_state': search_state,
            'node': node,
            'module': module
        }

        # load opened nodes from session
        opened_categories = list(
            request.session.setdefault(
                OPENED_CATEGORIES_KEY,
                set()
                # set(ThreadCategory.objects.filter(display_opened=True).values_list("pk", flat=True))
            )
        )
        template_data.update({"opened_categories": opened_categories})

        template_file = NODE_MODULE_TEMPLATE_FILE[module]

        if module == 'library':

            # get categories (with path to root) with thread (documents) with is unread
            # maybe is better way to create document/category tree structure in python and in template only render.

            categories_ids_witn_unread_thread = set()

            def _recursively(categories):
                for category in categories.iterator():
                    for thread in category.threads.iterator():
                        if thread.has_unread_main_post_for_user(request.user):
                            categories_ids_witn_unread_thread.update(
                                category.get_ancestors(include_self=True).values_list("pk", flat=True)
                            )
                            break
                    _recursively(category.get_children())
            _recursively(node.thread_categories.filter(level=0))

            ####################################################################

            template_data.update({
                "download_zip_form": DownloadZipForm(),
                "free_threads": node.threads.filter(is_deleted=False, category=None, thread_type=const.THREAD_TYPE_DOCUMENT).order_by("title"),  # Thread.objects.filter(thread__node=node, thread__category=None).select_related("thread"),
                "categories_ids_witn_unread_thread": categories_ids_witn_unread_thread
                # "categorized_threads": node.threads.exclude(category=None),  # Thread.objects.filter(thread__node=node, thread__category=None).select_related("thread"),
                # "free_documents": Document.objects.filter(thread__node=node, thread__category=None).select_related("thread"),
                # "category_documents": Document.objects.filter(thread__node=node).exclude(thread__category=None),
            })
        node.visit(request.user)
        return render_into_skin(template_file, template_data, request)

def node_module_forum(request, node_id, node_slug, module, **kwargs):
    """
    Forum module bypass. Direct render only one discussion
    """

    node = get_object_or_404(Node, pk=node_id, module_forum=True)
    thread_qs = node.threads.filter(
        thread_type=const.THREAD_TYPE_BY_NODE_MODULE[module]
    )[:1]

    if not (thread_qs.exists() or request.user.is_authenticated()):
        raise Http404

    if thread_qs:
        thread = thread_qs[0]
    else:
        post = request.user.post_thread(
            title=node.title,
            body_text="",
            timestamp=datetime.datetime.now(),
            node=node,
            thread_type=const.THREAD_TYPE_BY_NODE_MODULE[module]
        )
        thread = post.thread
    return HttpResponseRedirect(thread.get_absolute_url())

def node_module(request, node_id, node_slug, module, **kwargs):
    """
    node detail modulu

    thread_type -> setup Thread.thread_type or summary
    """
    # bypass for forum module
    if module == const.NODE_MODULE_FORUM:
        return node_module_forum(request, node_id, node_slug, module, **kwargs)

    node = get_object_or_404(Node, pk=node_id)

    if module in node.get_modules() and module not in [m[0] for m in node.get_modules()]:
        raise Http404()

    if node.slug != node_slug:
        return HttpResponseRedirect(reverse('node_module', kwargs={'node_id': node.pk, 'node_slug': node.slug, 'module': module}))

    if not request.user.has_openode_perm('node_read', node):
        if node.visibility == const.NODE_VISIBILITY_SEMIPRIVATE:
            return node_ask_to_join(request, node.pk, node.slug)
        return render_forbidden(request)

    if request.method != 'GET':
        return HttpResponseNotAllowed(['GET'])

    if module in const.THREAD_TYPE_BY_NODE_MODULE:
        return node_module_thread(request, node, module, **kwargs)

    template_file = NODE_MODULE_TEMPLATE_FILE[module]
    template_data = {
        'node': node,
        'module': module
    }

    if module == const.NODE_MODULE_ANNOTATION:
        try:
            page_no = int(request.GET.get("page", 1))
        except ValueError:
            page_no = 1

        end = LIVE_PER_PAGE * page_no
        start = end - LIVE_PER_PAGE
        template_data.update({
            "live_threads": get_live_data(request.user, start, end, node),
            "page": page_no,
            "check_perm": check_perm
        })

    return render_into_skin(template_file, template_data, request)

def revisions(request, id, post_type=None):
    assert post_type in ('question', 'answer')
    post = get_object_or_404(models.Post, post_type=post_type, id=id)
    revisions = list(models.PostRevision.objects.filter(post=post))
    revisions.reverse()
    for i, revision in enumerate(revisions):
        if i == 0:
            revision.diff = bleach_html(revisions[i].html)
            revision.summary = _('initial version')
        else:
            revision.diff = htmldiff(
                bleach_html(revisions[i - 1].html),
                bleach_html(revision.html)
            )

    data = {
        'page_class': 'revisions-page',
        'active_tab': 'questions',
        'post': post,
        'revisions': revisions,
    }
    return render_into_skin('revisions.html', data, request)

@csrf.csrf_exempt
@ajax_only
@anonymous_forbidden
@get_only
def get_comment(request):
    """returns text of a comment by id
    via ajax response requires request method get
    and request must be ajax
    """
    id = int(request.GET['id'])
    comment = models.Post.objects.get(post_type='comment', id=id)
    request.user.assert_can_edit_comment(comment)
    return {'text': comment.text}

def set_lang(request):
    language = request.GET.get('language', '')
    if language in [lang[0] for lang in getattr(settings, 'LANGUAGES', ())]:
        request.session['language'] = language
    next = request.GET.get('next', '/')
    return HttpResponseRedirect(next)

def thread_followers(request, node_id, node_slug, module, thread_id, thread_slug):

    node = get_object_or_404(Node, pk=node_id)
    thread = get_object_or_404(Thread, pk=thread_id, node=node)

    if node.slug != node_slug or thread.slug != thread_slug:
        return HttpResponseRedirect(reverse('thread_followers', kwargs={
            'node_id': node_id,
            'node_slug': node.slug,
            'module': module,
            'thread_id': thread_id,
            'thread_slug': thread.slug,
        }))

    data = {
        'follows': thread.thread_following_users.order_by("-added_at"),
        'thread': thread,
        'node': node,
        "can_make_remove_from_followers": node.node_users.filter(user=request.user, role=const.NODE_USER_ROLE_MANAGER).exists()
    }

    return render_into_skin('node/%s/followers.html' % thread.thread_type, data, request)

def thread_last_visit(request, node_id, node_slug, module, thread_id, thread_slug):
    """
    """
    LIMIT = 100
    node = get_object_or_404(Node, pk=node_id)
    thread = get_object_or_404(Thread, pk=thread_id, node=node)

    if node.slug != node_slug or thread.slug != thread_slug:
        return HttpResponseRedirect(reverse('thread_last_visit', kwargs={
            'node_id': node_id,
            'node_slug': node.slug,
            'module': module,
            'thread_id': thread_id,
            'thread_slug': thread.slug
        }))

    data = {
        'thread_viewed': thread.viewed.all().order_by("-last_visit")[:LIMIT],
        'thread': thread,
        "is_limit_overflow": thread.viewed.count() > LIMIT
    }

    return render_into_skin('node/%s/last_visit.html' % thread.thread_type, data, request)

def discussion_answer(request, pk):
    try:
        post = Post.objects.get(pk=pk)
        thread = post.thread
        node = thread.node
    except ObjectDoesNotExist:
        raise Http404

    if not request.user.has_openode_perm('discussion_read', node):
        return render_forbidden(request)

    to_tmpl = {
        "answer": post,
        "posts_per_pages": {}
    }
    return render_into_skin('node/discussion/discussion_answer.html', to_tmpl, request)


############################################################
#### Gillespie algorithm for ProcProc Model                #
#### Written by Abhishek Mallela                           #
#### Pseudocode + algorithm developed with Eric J. Deeds   #
#### Latest Version: 8/18/16                               #
############################################################

import numpy as np
from numpy import *
import random
import scipy.io

Mon = 1e-5 # This is for r = ratio of V_max's = 1e-2
Don = 1e-5 # Stochastic 'on' rate
r1 = 2e-5
r2 = 2e-4
Moff = 1e-1 # This is for r = ratio of V_max's = 1e-2; keeping K_M the same
Doff = 1e-1 # Stochastic, deterministic: same
Mcat2 = 1-1e-3 # This is for r = ratio of V_max's = 1e-2; keeping K_M the same
Mcat1 = Mcat2/100 # Because it takes longer to add the first ubiquitin unit
Dcat = 1-1e-3 # Stochastic, deterministic: same

def gillespie(maxtime=1e6):
    #### Initial declarations
    num = 1000 # S_init
    c = 0
    Q = r1*num # Defining it this way so that 'num' is the only quantity to change
    v0 = np.zeros((num)) # Row vector of 'num'-many zeros. Each element represents an S0 molecule
    v1 = np.empty((c)) # Empty row vector for v1; container for S1 to S3
    v2 = np.empty((c)) # Empty row vector for v2; container for S4 to Sl
    v3 = np.empty((c)) # Empty row vector for v3; container for MS0 to MS3
    v4 = np.empty((c)) # Empty row vector for v4; container for DS0 to DS3
    v5 = np.empty((c)) # Empty row vector for v5; container for MS4 to MSl
    v6 = np.empty((c)) # Empty row vector for v6; container for DS4 to DSl
    M_un = 100 # M_init
    D_un = 100 # D_init

## Begin Stochastic Simulation Algorithm (Doob-Gillespie)
    time = 0
    while (time < maxtime):
        tot = [Q, r1*len(v1), r2*len(v2), r1*len(v3), r1*len(v4), +
    					r2*len(v5), r2*len(v6), Mon*M_un*len(v1), +
    					Don*D_un*len(v1), Mon*M_un*len(v0), Don*D_un*len(v0), +
    					Mon*M_un*len(v2), Don*D_un*len(v2), Moff*len(v3), +
    					Doff*len(v4), Moff*len(v5), Doff*len(v6), +
    					Mcat1*(len(v3)-np.count_nonzero(v3)), +
    					Mcat2*np.count_nonzero(v3), +
    					Dcat*len(v4), Mcat2*len(v5), Dcat*len(v6)]
        for k in range(21):
            tot[k + 1] += tot[k]
        kT = tot[-1]
        time += -np.log(1-np.random.random())/kT

        if time >= maxtime:
            break

        event_kT = np.random.random() * kT
        #### Reaction 1: Synthesize a new S
        if event_kT < tot[0]:
            v0 = np.append(v0,0)
        #### Reaction 2: Delete a S from v1
        elif event_kT < tot[1]:
            k = random.randrange(len(v1))
            v1 = v1[np.arange(len(v1))!=k]
        #### Reaction 3: Delete a S from v2
        elif event_kT < tot[2]:
            k = random.randrange(len(v2))
            v2 = v2[np.arange(len(v2))!=k]
        #### Reaction 4: Delete a S from v3
        elif event_kT < tot[3]:
            k = random.randrange(len(v3))
            v3 = v3[np.arange(len(v3))!=k]
            M_un += 1
        #### Reaction 5: Delete a S from v4
        elif event_kT < tot[4]:
            k = random.randrange(len(v4))
            v4 = v4[np.arange(len(v4))!=k]
            D_un += 1
        #### Reaction 6: Delete a S from v5
        elif event_kT < tot[5]:
            k = random.randrange(len(v5))
            v5 = v5[np.arange(len(v5))!=k]
            M_un += 1
        #### Reaction 7: Delete a S from v6
        elif event_kT < tot[6]:
            k = random.randrange(len(v6))
            v6 = v6[np.arange(len(v6))!=k]
            D_un += 1
        #### Reaction 8: Bind a M to an S in v1
        elif event_kT < tot[7]:
            k = random.randrange(len(v1))
            v1temp = v1[np.arange(len(v1))!=k]
            v1rem = v1[k]
            v1 = v1temp
            if (v1rem > 0 and v1rem < 4):
                v3 = np.append(v3,v1rem)
            elif (v1rem >= 4):
                v5 = np.append(v5,v1rem)
            M_un -= 1
        #### Reaction 9: Bind a D to an S in v1
        elif event_kT < tot[8]:
            k = random.randrange(len(v1))
            v1temp = v1[np.arange(len(v1))!=k]
            v1rem = v1[k]
            v1 = v1temp
            if (v1rem > 0 and v1rem < 4):
                v4 = np.append(v4,v1rem)
            elif (v1rem >= 4):
                v6 = np.append(v6,v1rem)
            D_un -= 1
        #### Reaction 10: Bind a M to an S in v0
        elif event_kT < tot[9]:
            k = random.randrange(len(v0))
            v0temp = v0[np.arange(len(v0))!=k]
            v0rem = v0[k]
            v0 = v0temp
            v3 = np.append(v3,v0rem)
            M_un -= 1
        #### Reaction 11: Bind a D to an S in v0
        elif event_kT < tot[10]:
            k = random.randrange(len(v0))
            v0temp = v0[np.arange(len(v0))!=k]
            v0rem = v0[k]
            v0 = v0temp
            v4 = np.append(v4,v0rem)
            D_un -= 1
        #### Reaction 12: Bind a M to an S in v2
        elif event_kT < tot[11]:
            k = random.randrange(len(v2))
            v2temp = v2[np.arange(len(v2))!=k]
            v2rem = v2[k]
            v2 = v2temp
            v5 = np.append(v5,v2rem)
            M_un -= 1
        #### Reaction 13: Bind a D to an S in v2
        elif event_kT < tot[12]:
            k = random.randrange(len(v2))
            v2temp = v2[np.arange(len(v2))!=k]
            v2rem = v2[k]
            v2 = v2temp
            v6 = np.append(v6,v2rem)
            D_un -= 1
        #### Reaction 14: Unbind a M from v3
        elif event_kT < tot[13]:
            k = random.randrange(len(v3))
            v3temp = v3[np.arange(len(v3))!=k]
            v3rem = v3[k]
            if v3rem == 0:
                v0 = np.append(v0,v3rem)
            elif v3rem > 0:
                v1 = np.append(v1,v3rem)
            v3 = v3temp
            M_un += 1
        #### Reaction 15: Unbind a D from v4
        elif event_kT < tot[14]:
            k = random.randrange(len(v4))
            v4temp = v4[np.arange(len(v4))!=k]
            v4rem = v4[k]
            if v4rem == 0:
                v0 = np.append(v0,v4rem)
            elif v4rem > 0:
                v1 = np.append(v1,v4rem)
            v4 = v4temp
            D_un += 1
        #### Reaction 16: Unbind a M from v5
        elif event_kT < tot[15]:
            k = random.randrange(len(v5))
            v5temp = v5[np.arange(len(v5))!=k]
            v5rem = v5[k]
            v2 = np.append(v2,v5rem)
            v5 = v5temp
            M_un += 1
        #### Reaction 17: Unbind a D from v6
        elif event_kT < tot[16]:
            k = random.randrange(len(v6))
            v6temp = v6[np.arange(len(v6))!=k]
            v6rem = v6[k]
            v2 = np.append(v2,v6rem)
            v6 = v6temp
            D_un += 1
        #### Reaction 18: M catalysis for Mcat1 reaction in v3
        elif event_kT < tot[17]:
            k = random.randrange(len(v3))
            if v3[k] == 0:
                v3[k] += 1
        #### Reaction 19: M catalysis for Mcat2 reactions in v3
        elif event_kT < tot[18]:
            k = random.randrange(len(v3))
            if v3[k] == 1 or v3[k] == 2 or v3[k] == 3:
                v3[k] += 1
                if v3[k] > 3:
                    v5 = np.append(v5,v3[k])
                    v3 = v3[np.arange(len(v3))!=k]
        #### Reaction 20: D catalysis for v4
        elif event_kT < tot[19]:
            k = random.randrange(len(v4))
            v4[k] -= 1
            if v4[k] == 0:
                v4 = v4[np.arange(len(v4))!=k]
                v0 = np.append(v0,0)
        #### Reaction 21: M catalysis for v5
        elif event_kT < tot[20]:
            k = random.randrange(len(v5))
            v5[k] += 1
        #### Reaction 22: D catalysis for v6
        elif event_kT < tot[21]:
            k = random.randrange(len(v6))
            v6[k] -= 1
            if v6[k] == 3:
                v4 = np.append(v4,v6[k])
                v6 = v6[np.arange(len(v6))!=k]

    l0 = len(v0)
    l1 = len(v1)
    l2 = len(v2)
    l3 = len(v3)
    l4 = len(v4)
    l5 = len(v5)
    l6 = len(v6)
    l7 = max(v2)
    return l0, l1, l2, l3, l4, l5, l6, l7

if __name__ == '__main__':
    a = gillespie()
    scipy.io.savemat('ProcProc1.mat',dict(Smod=a[2]/10,Stot=sum(a)/10 - a[7]/10,lmax = a[7]))


from django.contrib import admin

from chat.models import Thread, Message

@admin.register(Thread)
class ThreadAdmin(admin.ModelAdmin):
    list_display = ('id', 'participants_list')

    def participants_list(self, obj):
        return ", ".join([str(user) for user in obj.participants.all()])

@admin.register(Message)
class MessageAdmin(admin.ModelAdmin):
    list_display = ('id', 'thread_id', 'sender', 'text', 'created', 'is_read')
    list_filter = ('thread__id', 'sender', 'is_read')
    search_fields = ('text', 'sender__username')


import os
import urllib

from flask import Flask, redirect
from flask import render_template
from flask import request

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        text = request.form['texto']
        ddd = request.form['ddd']
        number = request.form['numero']
        text_encoded = urllib.parse.urlencode({"text": text})
        url = f"https://wa.me/55{ddd}{number}?{text_encoded}"
        return redirect(url)
    return render_template('index.html', name=index)

if __name__ == "__main__":
    port = int(os.environ.get("PORT", 5000))
    app.run(host='0.0.0.0', port=port)


from app.models import App
from hashlib import sha256
from datetime import datetime, timedelta
from django.conf import settings
from django.core.files.storage import default_storage
from PIL import Image
import uuid

class GetFileServices:

    SIZE = {
        'xl': 1280,
        'lg': 960,
        'md': 720,
        'sm': 480,
        'xs': 240,
        'avatar': 120,
    }

    def __init__(self, file_type, folder_name, extension, size):
        self.file_type = file_type
        self.folder_name = folder_name
        self.extension = extension
        self.size = size
        self.error = None

    def is_valid(self):
        return self.error is None

    def is_exist_default(self):
        path_storage = settings.MEDIA_ROOT + '%s/%s/default.%s'%(self.file_type, self.folder_name, self.extension)
        if (not default_storage.exists(path_storage)):
            return False
        return True

    def is_valid_size(self):
        return ( self.SIZE.get(self.size, False)
            or self.size == 'default' )

    def get_file(self):
        if(self.file_type == 'files' or self.file_type == 'videos'):
            return self.get_default_file()

        if(self.file_type == 'images'):
            if(not self.is_valid_size()):
                self.error = 'Invalid size'
                return None

            if (self.size == 'default'):
                return self.get_default_file()
            else:
                return self.get_file_by_size()

    def get_default_file(self):
        path_url = '/media/%s/%s/default.%s' % (self.file_type, self.folder_name, self.extension)
        return path_url

    def get_file_by_size(self):
        if(not self.is_exist_default()):
            return self.get_default_file()

        path_url = '/media/%s/%s/%s.%s' % (
            self.file_type,
            self.folder_name,
            self.size,
            self.extension)
        path_storage = settings.MEDIA_ROOT + '%s/%s/%s.%s'%(
            self.file_type,
            self.folder_name,
            self.size,
            self.extension)

        if (not default_storage.exists(path_storage)):
            self.resize_and_save_image(path_storage)

        return path_url

    def resize_and_save_image(self, path_storage):
        default_path_storage = settings.MEDIA_ROOT + '%s/%s/default.%s'%(
                self.file_type,
                self.folder_name,
                self.extension)
        image = Image.open(default_path_storage)
        resize_image = self.resize_image(image, self.SIZE.get(self.size))
        resize_image.save(path_storage)

    def resize_image(self, image, newWidth):
        width, height = image.size
        newHeight = (int)(newWidth * height / width)
        resized_image = image.resize((newWidth, newHeight))
        return resized_image


import tkinter as tk
import tkcalendar as tkc
from datetime import datetime
from B_GUI import DateButton

class Calendar(tk.Frame):
    """
    A class GUI of Calendar.
    Imported date button from B_GUI

    Attributes
    ----------
    self :
        represents the instance of the class

    Methods
    ----------
    grab_date : returning of date which we choosing by clicking at Calendar
    """

    def __init__(self):
        super(Calendar, self).__init__()
        # calendar
        self.cal = tkc.Calendar(selectmode='day', date_pattern='dd-mm-yyyy')
        self.cal.place(x=50, y=50)
        # place for date what we chose
        self.my_label = tk.Label(text='')
        self.my_label.place(x=140, y=250)
        # button to access date
        self.btn = DateButton('Grab', self.grab_date)
        self.a = self.grab_date()
        print(self.a)

    def grab_date(self):
        """
        Method for taking date from calendar
        :return: str
            variable - string
        """
        self.my_label.config(text=self.cal.get_date())
        b = self.my_label.cget("text")
        return b


import collections
import re

def process_lists(file):
    with open(file, "r") as f:
        content_list = f.read().splitlines()
        return list(map(str.rstrip, content_list))

def count_legal_language(text, language):
    if language == 'es':
        legal_tokens = process_lists(
            './data/vocab-lists/ES-legal-penal(UTF8).txt')
    else:
        return 0
    return sum(1 for word in legal_tokens for _ in
               re.finditer(r'\b%s\b' % re.escape(word), text, re.IGNORECASE))

def count_medical_language(text, language):
    if language == 'ca':
        medical_tokens = process_lists('./data/vocab-lists/CA-med(UTF8).txt')
    elif language == 'es':
        medical_tokens = process_lists('./data/vocab-lists/ES-med(UTF8).txt')
    else:
        return 0
    return sum(1 for word in medical_tokens for _ in
               re.finditer(r'\b%s\b' % re.escape(word), text, re.IGNORECASE))

def count_most_common(text, language):
    if language == 'ca':
        most_common_tokens = process_lists(
            './data/vocab-lists/CA-8000_tokens_mas_frec_(UTF8).txt')
    elif language == 'es':
        most_common_tokens = process_lists(
            './data/vocab-lists/ES-10000_tokens_mas_frec_(UTF8).txt')
    else:
        return 0

    text_words = collections.Counter(re.split(r'\W+', text.lower()))
    # 1K
    count_1k = sum(filter(None, (text_words.get(word) for word in
                                 most_common_tokens[:1000])))
    # count_1k = sum(1 for word in most_common_tokens[:1000] for _ in
    #                re.finditer(r'\b%s\b' % re.escape(word), text,
    #                            re.IGNORECASE))

    # 1k 5k
    count_1k_5k = sum(filter(None, (text_words.get(word) for word in
                                    most_common_tokens[1000:5000])))
    # 5k  ...
    count_5k_10k = sum(filter(None, (text_words.get(word) for word in
                                     most_common_tokens[5000:])))

    return count_1k, count_1k_5k, count_5k_10k


from typing import Optional, Tuple
from unicodedata import normalize as unicode_normalize

from ._phonetic import _Phonetic

__all__ = ['Waahlin']

class Waahlin(_Phonetic):
    """Wåhlin code.

    Wåhlin's first-letter coding is based on the description in
    :cite:`Erikson:1997`.

    .. versionadded:: 0.3.6
    """

    def __init__(self, encoder: Optional[_Phonetic] = None) -> None:
        """Initialize Waahlin instance.

        Parameters
        ----------
        encoder : _Phonetic
            An initialized phonetic algorithm object

        .. versionadded:: 0.4.0

        """
        self._encoder = encoder

    _transforms = {
        3: {'SCH': '*', 'STJ': '*', 'SKJ': '*'},
        2: {
            'AE': 'E',
            'CH': 'K',
            'DJ': 'J',
            'GJ': 'J',
            'HJ': 'J',
            'HV': 'V',
            'HW': 'V',
            'HR': 'R',
            'KJ': '+',
            'LJ': 'J',
            'PH': 'F',
            'QU': 'KV',
            'SJ': '*',
            'TJ': '+',
        },
        1: {'Q': 'K', 'W': 'V', 'Z': 'S', 'Ä': 'E'},
    }

    def _encode_next(self, word: str) -> Tuple[str, str]:
        if word[:3] == 'STI' and word[3:4] in {'E', 'Ä'}:
            code = '*'
            remainder = word[3:]
        elif word[:3] in self._transforms[3]:
            code = self._transforms[3][word[:3]]
            remainder = word[3:]
        elif word[:2] == 'HI' and word[2:3] in {
            'A',
            'E',
            'I',
            'O',
            'U',
            'Y',
            'Å',
            'Ä',
            'Ö',
        }:
            code = 'J'
            remainder = word[2:]
        elif word[:2] == 'SK' and word[2:3] in {'E', 'I', 'Y', 'Ä', 'Ö'}:
            code = '*'
            remainder = word[2:]
        elif word[:2] in self._transforms[2]:
            code = self._transforms[2][word[:2]]
            remainder = word[2:]
        elif word[:1] == 'C' and word[1:2] in {'E', 'I', 'Y', 'Ä'}:
            code = 'S'
            remainder = word[1:]
        elif word[:1] == 'G' and word[1:2] in {'E', 'I', 'Y', 'Ä', 'Ö'}:
            code = 'J'
            remainder = word[1:]
        elif word[:1] == 'I' and word[1:2] in {
            'A',
            'E',
            'I',
            'O',
            'U',
            'Y',
            'Å',
            'Ä',
            'Ö',
        }:
            code = 'J'
            remainder = word[1:]
        elif word[:1] == 'K' and word[1:2] in {'E', 'I', 'Y', 'Ä', 'Ö'}:
            code = '+'
            remainder = word[1:]
        elif word[:1] in self._transforms[1]:
            code = self._transforms[1][word[:1]]
            remainder = word[1:]
        else:
            code = word[:1]
            remainder = word[1:]

        return code, remainder

    def encode_alpha(self, word: str) -> str:
        """Return the alphabetic Wåhlin code for a word.

        Parameters
        ----------
        word : str
            The word to transform

        Returns
        -------
        str
            The alphabetic Wåhlin code value

        Examples
        --------
        >>> pe = Waahlin()
        >>> pe.encode_alpha('Christopher')
        'KRISTOFER'
        >>> pe.encode_alpha('Niall')
        'NJALL'
        >>> pe.encode_alpha('Smith')
        'SMITH'
        >>> pe.encode_alpha('Schmidt')
        'ŠMIDT'

        .. versionadded:: 0.4.0

        """
        return (
            self.encode(word, alphabetic=True)
            .replace('+', 'Ç')
            .replace('*', 'Š')
        )

    def encode(self, word: str, alphabetic: bool = False) -> str:
        """Return the Wåhlin code for a word.

        Parameters
        ----------
        word : str
            The word to transform
        alphabetic : bool
            If True, the encoder will apply its alphabetic form (.encode_alpha
            rather than .encode)

        Returns
        -------
        str
            The Wåhlin code value

        Examples
        --------
        >>> pe = Waahlin()
        >>> pe.encode('Christopher')
        'KRISTOFER'
        >>> pe.encode('Niall')
        'NJALL'
        >>> pe.encode('Smith')
        'SMITH'
        >>> pe.encode('Schmidt')
        '*MIDT'

        .. versionadded:: 0.4.0

        """
        # uppercase, normalize, decompose, and filter non-A-Z out
        word = unicode_normalize('NFC', word.upper())
        if not word:
            return ''

        if self._encoder is None:
            code = ''
            while word:
                part, word = self._encode_next(word)
                code += part
            return code

        code, word = self._encode_next(word)
        return code + (
            self._encoder.encode_alpha(word)
            if alphabetic
            else self._encoder.encode(word)
        )

if __name__ == '__main__':
    import doctest

    doctest.testmod()


__copyright__ = "Copyright (c) 2020-2021 Jina AI Limited. All rights reserved."
__license__ = "Apache-2.0"

from typing import Dict, Iterable, Optional

import numpy as np
import tensorflow as tf
from jina import DocumentArray, Executor, requests
from jina.logging.logger import JinaLogger

class ImageTFEncoder(Executor):
    """
    :class:`ImageTFEncoder` encodes ``Document`` content from a ndarray,
    potentially B x (Height x Width x Channel) into a ndarray of `B x D`.

    Where `B` is the batch size and `D` is the Dimension.

    The :class:`ImageTFEncoder` wraps the models from
    `tensorflow.keras.applications`.
    <https://www.tensorflow.org/api_docs/python/tf/keras/applications>`_
    """

    def __init__(
        self,
        model_name: str = 'MobileNetV2',
        img_shape: int = 336,
        pool_strategy: str = 'max',
        traversal_paths: Iterable[str] = ('r',),
        batch_size: int = 32,
        device: str = '/CPU:0',
        *args,
        **kwargs,
    ):
        """
        :param model_name: the name of the model. Supported models include
            ``DenseNet121``, ``DenseNet169``, ``DenseNet201``,
            ``InceptionResNetV2``, ``InceptionV3``, ``MobileNet``,
            ``MobileNetV2``, ``NASNetLarge``, ``NASNetMobile``,
            ``ResNet101``, ``ResNet152``, ``ResNet50``, ``ResNet101V2``,
            ``ResNet152V2``, ``ResNet50V2``, ``VGG16``, ``VGG19``,
            ``Xception`` and etc. A full list can be find at
            <https://www.tensorflow.org/api_docs/python/tf/keras/applications#functions>`_
        :param img_shape: The shape of the image to be encoded.
        :param pool_strategy: the pooling strategy. Options are:
            - `None`: Means that the output of the model will be the 4D tensor
                output of the last convolutional block.
            - `avg`: Means that global average pooling will be applied to the
                output of the last convolutional block, and thus the output of
                the model will be a 2D tensor.
            - `max`: Means that global max pooling will be applied.
        :param traversal_paths: traversal path of the Documents, (e.g. 'r', 'c')
        :param batch_size: size of each batch
        :param device: Device ('/CPU:0', '/GPU:0', '/GPU:X')
        """
        super().__init__(*args, **kwargs)
        self.model_name = model_name
        self.pool_strategy = pool_strategy
        self.img_shape = img_shape
        self.batch_size = batch_size
        self.traversal_paths = traversal_paths
        self.logger = JinaLogger(self.__class__.__name__)

        gpus = tf.config.experimental.list_physical_devices(device_type='GPU')
        if 'GPU' in device:
            gpu_index = 0 if 'GPU:' not in device else int(device.split(':')[-1])
            if len(gpus) < gpu_index + 1:
                raise RuntimeError(f'Device {device} not found on your system!')
        self.device = tf.device(device)

        with self.device:
            model = getattr(tf.keras.applications, self.model_name)(
                input_shape=(self.img_shape, self.img_shape, 3),
                include_top=False,
                pooling=self.pool_strategy,
                weights='imagenet',
            )
            model.trainable = False
            self.model = model

    @requests
    def encode(
        self, docs: Optional[DocumentArray] = None, parameters: Dict = {}, **kwargs
    ):
        """
        Encode document 'blob' into one-dimentional vector and store it into `embedding`.

        :param docs: `DocumentArray` containing `Document`s with the `blob` of image data
            in the size of `Height x Width x 3`. The `dtype` of the `blob` must be `float32`.
            The `blob` must be preprocessed to `[0, 1]`. Check out the preprocessed module of
            different models at https://www.tensorflow.org/api_docs/python/tf/keras/applications#functions
        :param parameters: dictionary to define the `traversal_paths` and the `batch_size`.
            For example, `parameters={'traversal_paths': ['r'], 'batch_size': 10}` will
            override the `self.traversal_paths` and `self.batch_size`.
        """
        if docs:
            document_batches_generator = docs.traverse_flat(
                traversal_paths=parameters.get('traversal_paths', self.traversal_paths),
                filter_fn=lambda doc: doc.blob is not None,
            ).batch(
                batch_size=parameters.get('batch_size', self.batch_size),
            )
            self._create_embeddings(document_batches_generator)

    def _create_embeddings(self, document_batches_generator: Iterable):
        for document_batch in document_batches_generator:
            blob_batch = np.stack([d.blob for d in document_batch])
            with self.device:
                embedding_batch = self.model(blob_batch)
            for document, embedding in zip(document_batch, embedding_batch):
                document.embedding = np.array(embedding)


import os
from pyrogram import Client
import logging
import config
import tracemalloc
from pyromod import listen

from plugins.eval import remove_if_exists

tracemalloc.start()

api = config.API_ID
hash = config.API_HASH
token = config.BOT_TOKEN
# session = config.SESSION

bot = Client(
    "memadder",
    api_id = api,
    api_hash = hash,
    bot_token = token,
    plugins=dict(root="plugins"),
    # in_memory=True,
)

remove_if_exists('logs.txt')
remove_if_exists("unknown_errors.txt")
remove_if_exists("my_account.session")

logging.basicConfig(
  filename=f'logs.txt',
  level=logging.INFO,
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logging.getLogger("pyrogram").setLevel(logging.ERROR)
logging.getLogger("pyrogram").setLevel(logging.WARNING)

LOGS = logging.getLogger(__name__)


import numpy as np
import random
import names
import copy
import sys
import time
from matplotlib import pyplot as plt
from matplotlib import animation

if len(sys.argv) < 4:
    print('---------------------------------')
    print('Need to get the parameters in the form of: ')
    print('number_of_cities(int) population_number_per_generation(int) mutation_rate(float, in percent) power_scoring(int)')
    print('For example: python this_script.py 15 100 80 2')
    print('---------------------------------')
    sys.exit()
else:
    num_cities=int(sys.argv[1])
    pop_number=int(sys.argv[2])
    mutation_rate=float(sys.argv[3])
    pow_score=int(sys.argv[4])

# Initialize random cities with random names

cities=[]
class City:
    def __init__(self,x,y,name):
        self.name=name
        self.x=x
        self.y=y

for i in range(num_cities):
    x=random.random()*100
    y=random.random()*100
    city=City(x,y,names.get_first_name())
    cities.append(city)

def dist_between(city1,city2):
    x_tmp=abs(city1.x-city2.x)
    y_tmp=abs(city1.y-city2.y)
    return np.sqrt(pow(x_tmp,2)+pow(y_tmp,2))

def crossover(ADN1,ADN2):
    cur_parrent=copy.copy(ADN1.list_cities),copy.copy(ADN2.list_cities)
    curr=0
    child=[]
    while len(child)<num_cities:
        if len(cur_parrent[curr])==1:
            child.append(cur_parrent[(curr+1)%2].pop(0))
            return ADN(child)
        i_ind=cur_parrent[curr].pop(0)
        j_ind=cur_parrent[curr].pop(0)
        child.append(i_ind)
        child.append(j_ind)
        cur_parrent[(curr+1)%2].remove(i_ind)
        cur_parrent[(curr+1)%2].remove(j_ind)
        curr=(curr+1)%2
    return ADN(child)

def get_tot_dist(cities_list):
    tot_dist=0
    for i in range(len(cities_list)-1):
        tot_dist+=dist_between(cities_list[i],cities_list[i+1])
    return tot_dist

def random_shuffle(array):
    res=[]
    l=len(array)
    while len(res)!=l:
        res.append(array.pop(random.randint(0,len(array)-1)))
    return res

class ADN:
    def __init__(self,cities):
        self.list_cities=cities
        self.fitness=0
        self.score=0

    def __str__(self):
        res=''
        for city in self.list_cities:
            res+=str(city.name)+'-->'
        return res[:-3]

    def mutate(self,mut_rate):
        if random.random() <= mut_rate/100:
            i= random.randint(0,len(self.list_cities)-1)
            j= random.randint(0,len(self.list_cities)-1)
            temp=self.list_cities[i]
            self.list_cities[i]=self.list_cities[j]
            self.list_cities[j]=temp

class Population:

    def __init__(self,N,mut_rate,popopow):
        self.N=N
        self.mut_rate=mut_rate
        self.pop=[]
        self.popopow=popopow

        for i in range(N):
            ind=ADN(random_shuffle(copy.copy(cities)))
            self.pop.append(ind)
        self.evaluate_fitness()

    def evaluate_fitness(self):
        sum_score=0
        for ind in self.pop:
            ind.score=get_tot_dist(ind.list_cities)
            sum_score+=1/pow(ind.score,self.popopow)
        for ind in self.pop:
            ind.fitness=1/pow(ind.score,self.popopow)/sum_score

    def pick(self):
        index=0
        selector=random.random()
        while selector > 0:
            selector-=self.pop[index].fitness
            index+=1
        index-=1
        return self.pop[index]

    def next_gen(self):
        new_pop=[]
        for i in range(self.N):
            parent1=self.pick()
            parent2=self.pick()
            child=crossover(parent1,parent2)
            child.mutate(self.mut_rate)
            new_pop.append(child)
        self.pop=new_pop

    def evaluate(self):
        best_fit=0
        best_ind=self.pop[0]
        for ind in self.pop:
            if ind.fitness > best_fit:
                best_fit= ind.fitness
                best_ind=ind
        return best_ind

    def overall_score(self):
        sum_score=0
        for ind in self.pop:
            sum_score+=ind.score
        return sum_score/pop_number

    def __call__(self):
        #make the next_generation and return the best ind of the new gen
        self.next_gen()
        self.evaluate_fitness()
        return self.evaluate(),self.overall_score()

# Genetic algorythm
pop=Population(pop_number,mutation_rate,pow_score)

# print the infos
fig=plt.figure(1)
ax = plt.axes(xlim=(0, 200), ylim=(0, 100))
plt.xticks([]), plt.yticks([])

line, = ax.plot([], [], marker="o",lw=2,color="green")
line2, = ax.plot([], [], marker="o", lw=2,color="red")

def frames():
    best_dist=float('inf')
    best_path=None
    gen=1
    while True:
        best_ind=pop()[0]
        best_score=best_ind.score
        oa_score=pop()[1]
        if (best_ind.score) < best_dist:
            best_dist=best_ind.score
            best_path=best_ind
        # print(best_score)
        gen+=1
        yield best_ind,best_path,oa_score,gen

def animate(args):
    x=[]
    y=[]
    x2=[]
    y2=[]
    for city in args[0].list_cities:
        x.append(city.x)
        y.append(city.y)
    for city in args[1].list_cities:
        x2.append(city.x+100)
        y2.append(city.y)
    line.set_data(x, y)
    line2.set_data(x2, y2)
    fig.suptitle('Current best (green): '+str(int(args[0].score))+'\n    Best of all (red): '+str(int(args[1].score)))
    return line,line2

anim = animation.FuncAnimation(fig, animate, frames=frames, interval=1)

# fig2=plt.figure(2)

# x=[]
# y=[]
# y2=[]

# def animate2(args):
#     x.append(args[3])
#     y.append(args[2])
#     y2.append(args[0].score)
#     plt.plot(x, y, color='g')
#     plt.plot(x, y2, color='orange')

# anim2 = animation.FuncAnimation(fig2, animate2, frames=frames, interval=1)

plt.show()


import scipy
import torch
from torch import nn
from torch.nn import functional as F
from torchvision import models
import numpy as np
from scipy import linalg
from scipy.stats import entropy

class GANLoss(nn.Module):
    """
    GAN loss calculator

    Variants:
      - non_saturating
      - hinge
    """
    def __init__(self, loss_type):
        super(GANLoss, self).__init__()
        self.loss_type = loss_type

    def forward(self, fake_scores, real_scores=None):
        if real_scores is None:
            # TODO: calculate generator loss (2 points)
            if self.loss_type == 'non_saturating':
                loss = -fake_scores.sigmoid().log().mean()
            else:  # hinge loss
                loss = -fake_scores.mean()

        else:
            # TODO: calculate discriminator loss (2 points)
            if self.loss_type == 'non_saturating':
                loss = -(real_scores.sigmoid().log() + (1 - fake_scores.sigmoid()).log()).mean()
            else:  # hinge loss
                loss = (1 - real_scores).relu().mean() + (1 + fake_scores).relu().mean()

        return loss

class ValLoss(nn.Module):
    """
    Calculates FID and IS
    """
    def __init__(self):
        super().__init__()
        self.inception_v3 = models.inception_v3(pretrained=True)
        self.inception_v3.eval()

        for p in self.inception_v3.parameters():
            p.requires_grad = False

    @torch.no_grad()
    def _features(self, x: torch.Tensor) -> torch.Tensor:
        # Preprocess data
        x = F.interpolate(x, size=(299, 299), mode='bilinear')
        x = (x - 0.5) * 2

        # N x 3 x 299 x 299
        x = self.inception_v3.Conv2d_1a_3x3(x)
        # N x 32 x 149 x 149
        x = self.inception_v3.Conv2d_2a_3x3(x)
        # N x 32 x 147 x 147
        x = self.inception_v3.Conv2d_2b_3x3(x)
        # N x 64 x 147 x 147
        x = self.inception_v3.maxpool1(x)
        # N x 64 x 73 x 73
        x = self.inception_v3.Conv2d_3b_1x1(x)
        # N x 80 x 73 x 73
        x = self.inception_v3.Conv2d_4a_3x3(x)
        # N x 192 x 71 x 71
        x = self.inception_v3.maxpool2(x)
        # N x 192 x 35 x 35
        x = self.inception_v3.Mixed_5b(x)
        # N x 256 x 35 x 35
        x = self.inception_v3.Mixed_5c(x)
        # N x 288 x 35 x 35
        x = self.inception_v3.Mixed_5d(x)
        # N x 288 x 35 x 35
        x = self.inception_v3.Mixed_6a(x)
        # N x 768 x 17 x 17
        x = self.inception_v3.Mixed_6b(x)
        # N x 768 x 17 x 17
        x = self.inception_v3.Mixed_6c(x)
        # N x 768 x 17 x 17
        x = self.inception_v3.Mixed_6d(x)
        # N x 768 x 17 x 17
        x = self.inception_v3.Mixed_6e(x)
        # N x 768 x 17 x 17
        x = self.inception_v3.Mixed_7a(x)
        # N x 1280 x 8 x 8
        x = self.inception_v3.Mixed_7b(x)
        # N x 2048 x 8 x 8
        x = self.inception_v3.Mixed_7c(x)
        # Adaptive average pooling
        x = self.inception_v3.avgpool(x)
        # N x 2048 x 1 x 1
        x = self.inception_v3.dropout(x)
        # N x 2048 x 1 x 1
        x = torch.flatten(x, 1)

        return x

    @torch.no_grad()
    def _classifier(self, x: torch.Tensor) -> torch.Tensor:
        # N x 2048
        x = self.inception_v3.fc(x)
        # N x 1000 (num_classes)
        x = F.softmax(x, dim=1)

        return x

    def calc_data(self, real_inputs: list, fake_inputs: list):
        real_features = []
        for real_inputs_batch in real_inputs:
            real_features_batch = self._features(real_inputs_batch)
            real_features.append(real_features_batch.detach().cpu().numpy())
        real_features = np.concatenate(real_features)

        fake_features = []
        fake_probs = []

        for fake_inputs_batch in fake_inputs:
            fake_features_batch = self._features(fake_inputs_batch)
            fake_probs_batch = self._classifier(fake_features_batch)

            fake_features.append(fake_features_batch.detach().cpu().numpy())
            fake_probs.append(fake_probs_batch.detach().cpu().numpy())

        fake_features = np.concatenate(fake_features)
        fake_probs = np.concatenate(fake_probs)

        return real_features, fake_features, fake_probs

    # This method incorporates the algorithm from https://github.com/mseitzer/pytorch-fid/blob/master/src/pytorch_fid/fid_score.py.
    @staticmethod
    def calc_fid(real_features, fake_features):

        mu1 = real_features.mean(axis=0)
        mu2 = fake_features.mean(axis=0)

        sigma1 = np.cov(real_features, rowvar=False)
        sigma2 = np.cov(fake_features, rowvar=False)

        diff = mu1 - mu2

        # Product might be almost singular.
        covmean, _ = linalg.sqrtm(sigma1 @ sigma2, disp=False)

        if not np.isfinite(covmean).all():
            eps = 1e-6
            print(f'fid calculation produces singular product; adding {eps} to diagonal of cov estimates')
            offset = np.eye(sigma1.shape[0]) * eps
            covmean = linalg.sqrtm((sigma1 + offset) @ (sigma2 + offset))

        # Numerical error might give slight imaginary component.
        if np.iscomplexobj(covmean):
            covmean = covmean.real

        tr_covmean = np.trace(covmean)

        return diff @ diff + np.trace(sigma1) + np.trace(sigma2) - 2 * tr_covmean

    # This method incorporates the algorithm from https://github.com/sbarratt/inception-score-pytorch/blob/master/inception_score.py.
    @staticmethod
    def calc_is(fake_probs):

        # Compute the mean kl-div.
        py = np.mean(fake_probs, axis=0)
        scores = []
        for i in range(fake_probs.shape[0]):
            pyx = fake_probs[i, :]
            scores.append(entropy(pyx, py))
        return np.exp(np.mean(scores))

    def forward(self, real_images: list, fake_images: list) -> torch.Tensor:
        real_features, fake_features, fake_probs = self.calc_data(real_images, fake_images)

        fid = self.calc_fid(real_features, fake_features)

        inception_score = self.calc_is(fake_probs)

        return fid, inception_score


import telebot
import os

bot = telebot.TeleBot('5575408189:AAGoFgDByNwwu0nMjz6oWcW5cFph5MH7a04')
toChatID = 548277486

@bot.message_handler(commands=['start']) # старт
def start(message):
    bot.send_message(message.chat.id, 'Привет. Отправляй мне мемы!')

@bot.message_handler(commands=['msg']) # связь
def msg(text):
    gsm = f'{text.text}'
    gsm = gsm.replace('/msg', '')
    gsm = gsm.split('+')
    user = gsm[0]
    info = gsm[1]
    user = user.replace(' ', '')
    bot.send_message(user, info)

@bot.message_handler() # связь с той стороны
def getUser(message):
    text = f'Сообщение от {message.from_user.first_name} {message.from_user.last_name}. ID: {message.from_user.id}. Тэг: @{message.from_user.username}'
    bot.send_message(toChatID, text)
    bot.forward_message(toChatID, message.chat.id, message.message_id)
    bot.send_message(message.chat.id, 'Отправлено!')

@bot.message_handler(content_types=["photo"]) # фото
def echo_msg(message):
    if message.content_type == 'photo':
        raw = message.photo[2].file_id
        name = raw + ".jpg"
        file_info = bot.get_file(raw)
        downloaded_file = bot.download_file(file_info.file_path)
        with open(name, 'wb') as new_file:
            new_file.write(downloaded_file)
        img = open(name, 'rb')
        bot.send_message(toChatID,
                         f"Предложка от {message.from_user.first_name} {message.from_user.last_name}",
                         parse_mode="Markdown")
        if message.from_user.username == None:
            print('')
        else:
            bot.send_message(toChatID, f'Tag: @{message.from_user.username}')
        bot.send_message(toChatID, f'ID: {message.from_user.id}')
        bot.send_photo(toChatID, img)
        bot.send_message(message.chat.id,
                         "Отправлено!",
                         parse_mode="Markdown")
        for root, dirs, files in os.walk("./"):
            for file in files:
                if file.endswith(".jpg"):
                    print(file)
                    os.remove(file)
                    break

@bot.message_handler(content_types=['video']) # видео
def echo_vid(message):
    file_info = bot.get_file(message.video.file_id)
    name = file_info.file_id + '.mp4'
    downloaded_file = bot.download_file(file_info.file_path)
    with open(name, 'wb') as new_file:
        new_file.write(downloaded_file)
    mp4 = open(name, 'rb')
    bot.send_message(toChatID,
                     f"Предложка от {message.from_user.first_name} {message.from_user.last_name}",
                     parse_mode="Markdown")
    if message.from_user.username == None:
        print('')
    else:
        bot.send_message(toChatID, f'Tag: @{message.from_user.username}')
    bot.send_message(toChatID, f'ID: {message.from_user.id}')
    bot.send_video(toChatID, mp4)
    bot.send_message(message.chat.id,
                     "Отправлено!",
                     parse_mode="Markdown")
    for root, dirs, files in os.walk("./"):
        for file in files:
            if file.endswith(".mp4"):
                print(file)
                os.remove(file)
                break

bot.polling(none_stop=True)


import requests
from bs4 import BeautifulSoup
import psycopg2
import time

# BD connect
connection = psycopg2.connect(database="metro", user="postgres", password="*****", host="localhost", port="5432")

# Postgresql add data
def add_data(values):
    cursor = connection.cursor()
    postgres_insert_query = """ INSERT INTO "news" (url, image, description, date) VALUES (%s,%s,%s,%s)"""
    record_to_insert = values
    cursor.execute(postgres_insert_query, record_to_insert)
    connection.commit()

# PG exist test
def exist_test(url):
    cur = connection.cursor()
    cur.execute("select url from news where url=%s", (url,))
    if cur.fetchone():
        return False
    else:
        return True

# Date converter
def convert_date(date):
    if "декабря" in date:
        return "2021-12-" + date.split(" ")[0]
    elif "ноября" in date:
        return "2021-11-" + date.split(" ")[0]
    elif "октября" in date:
        return "2021-10-" + date.split(" ")[0]
    elif "сентября" in date:
        return "2021-09-" + date.split(" ")[0]
    elif "августа" in date:
        return "2021-08-" + date.split(" ")[0]
    elif "июля" in date:
        return "2021-07-" + date.split(" ")[0]
    elif "июня" in date:
        return "2021-06-" + date.split(" ")[0]
    elif "мая" in date:
        return "2021-05-" + date.split(" ")[0]
    elif "апреля" in date:
        return "2021-04-" + date.split(" ")[0]
    elif "марта" in date:
        return "2021-03-" + date.split(" ")[0]
    elif "февраля" in date:
        return "2021-02-" + date.split(" ")[0]
    elif "января" in date:
        return "2021-01-" + date.split(" ")[0]

while True:
    # BS4 preparationpip
    url = "https://mosmetro.ru/news/"
    page = requests.get(url).text
    soup = BeautifulSoup(page, 'html.parser')
    news = soup.find_all("a", {"class": "news-card"})

    # Get description, url, date, image
    for i in range(len(news)):
        news_url = "https://mosmetro.ru" + news[i].get('href')
        news_image = news[i].find("div", {"class": "news-card__image"}).get('style').split('url(')[1][:-1]
        news_description = news[i].find("div", {"class": "news-card__caption"}).get_text()
        news_date = convert_date(news[i].find("div", {"class": "news-card__date"}).get_text())
        data = (news_url, news_image, news_description, news_date)
        if exist_test(news_url):
            add_data(data)
    time.sleep(600)


from abc import ABC, abstractmethod
from collections.abc import Set
from enum import Enum
from operator import (ge, gt, le, lt, eq, attrgetter, add, sub, mul, pow,
						truediv, floordiv, mod)
from functools import partial, wraps, cached_property
from contextlib import contextmanager
from textwrap import dedent
from time import monotonic
from types import MethodType, FunctionType
from typing import (Mapping, Iterable, Union, Callable, Dict, Hashable)

import numpy as np
import msgpack
import networkx as nx
from tblib import Traceback

from . import exc

class FinalRule:
	"""A singleton sentinel for the rule iterator"""
	__slots__ = []

	def __hash__(self):
		# completely random integer
		return 6448962173793096248

final_rule = FinalRule()

class MsgpackExtensionType(Enum):
	"""Type codes for packing special LiSE types into msgpack"""
	tuple = 0x00
	frozenset = 0x01
	set = 0x02
	exception = 0x03
	character = 0x7f
	place = 0x7e
	thing = 0x7d
	portal = 0x7c
	final_rule = 0x7b
	function = 0x7a
	method = 0x79
	trigger = 0x78
	prereq = 0x77
	action = 0x76

class get_rando:
	"""Attribute getter for randomization functions

	Aliases functions of a randomizer, wrapped so that they won't run in
	planning mode, and will save the randomizer's state after every call.

	"""
	__slots__ = ('_getter', '_wrapfun', '_instance')
	_getter: Callable

	def __init__(self, attr, *attrs):
		self._getter = attrgetter(attr, *attrs)

	def __get__(self, instance, owner) -> Callable:
		if hasattr(self, '_wrapfun') and self._instance is instance:
			return self._wrapfun
		retfun = self._getter(instance)

		@wraps(retfun)
		def remembering_rando_state(*args, **kwargs):
			if instance._planning:
				raise exc.PlanError("Don't use randomization in a plan")
			ret = retfun(*args, **kwargs)
			instance.universal['rando_state'] = instance._rando.getstate()
			return ret

		self._wrapfun = remembering_rando_state
		self._instance = instance
		return remembering_rando_state

@contextmanager
def timer(msg='', logfun: callable = None):
	if logfun is None:
		logfun = print
	start = monotonic()
	yield
	logfun("{:,.3f} {}".format(monotonic() - start, msg))

def getatt(attribute_name):
	"""An easy way to make an alias"""
	return property(attrgetter(attribute_name))

def singleton_get(s):
	"""Take an iterable and return its only item if possible, else None."""
	it = None
	for that in s:
		if it is not None:
			return None
		it = that
	return it

class EntityStatAccessor(object):
	__slots__ = [
		'engine', 'entity', 'branch', 'turn', 'tick', 'stat', 'current',
		'mungers'
	]

	def __init__(self,
					entity,
					stat,
					engine=None,
					branch=None,
					turn=None,
					tick=None,
					current=False,
					mungers: list = None):
		if engine is None:
			engine = entity.engine
		if branch is None:
			branch = engine.branch
		if turn is None:
			turn = engine.turn
		if mungers is None:
			mungers = []
		self.current = current
		self.engine = engine
		self.entity = entity
		self.stat = stat
		self.branch = branch
		self.turn = turn
		self.tick = tick
		self.mungers = mungers

	def __call__(self, branch=None, turn=None, tick=None):
		if self.current:
			res = self.entity[self.stat]
		else:
			branc, trn, tck = self.engine._btt()
			self.engine.branch = branch or self.branch
			self.engine.turn = turn if turn is not None else self.turn
			if tick is not None:
				self.engine.tick = tick
			elif self.tick is not None:
				self.engine.tick = self.tick
			if hasattr(self.entity, 'stat'):
				res = self.entity.stat[self.stat]
			else:
				res = self.entity[self.stat]
			self.engine._set_btt(branc, trn, tck)
		for munger in self.mungers:
			res = munger(res)
		return res

	def __ne__(self, other):
		return self() != other

	def __str__(self):
		return str(self())

	def __repr__(self):
		return "EntityStatAccessor({}[{}]{}), {} mungers".format(
			self.entity, self.stat,
			"" if self.current else ", branch={}, turn={}, tick={}".format(
				self.branch, self.turn, self.tick), len(self.mungers))

	def __gt__(self, other):
		return self() > other

	def __ge__(self, other):
		return self() >= other

	def __lt__(self, other):
		return self() < other

	def __le__(self, other):
		return self() <= other

	def __eq__(self, other):
		return self() == other

	def munge(self, munger):
		return EntityStatAccessor(self.entity, self.stat, self.engine,
									self.branch, self.turn, self.tick,
									self.current, self.mungers + [munger])

	def __add__(self, other):
		return self.munge(partial(add, other))

	def __sub__(self, other):
		return self.munge(partial(sub, other))

	def __mul__(self, other):
		return self.munge(partial(mul, other))

	def __rpow__(self, other, modulo=None):
		return self.munge(partial(pow, other, modulo=modulo))

	def __rdiv__(self, other):
		return self.munge(partial(truediv, other))

	def __rfloordiv__(self, other):
		return self.munge(partial(floordiv, other))

	def __rmod__(self, other):
		return self.munge(partial(mod, other))

	def __getitem__(self, k):
		return self.munge(lambda x: x[k])

	def iter_history(self, beginning, end):
		"""Iterate over all the values this stat has had in the given window, inclusive.

		"""
		# It might be useful to do this in a way that doesn't change the
		# engine's time, perhaps for thread safety
		engine = self.engine
		entity = self.entity
		oldturn = engine.turn
		oldtick = engine.tick
		stat = self.stat
		for turn in range(beginning, end + 1):
			engine.turn = turn
			try:
				y = entity[stat]
			except KeyError:
				yield None
				continue
			if hasattr(y, 'unwrap'):
				y = y.unwrap()
			yield y
		engine.turn = oldturn
		engine.tick = oldtick

def dedent_source(source):
	nlidx = source.index('\n')
	if nlidx is None:
		raise ValueError("Invalid source")
	while source[:nlidx].strip().startswith('@'):
		source = source[nlidx + 1:]
		nlidx = source.index('\n')
	return dedent(source)

def _sort_set_key(v):
	if isinstance(v, tuple):
		return (2, ) + tuple(map(repr, v))
	if isinstance(v, str):
		return 1, v
	return 0, repr(v)

_sort_set_memo = {}

def sort_set(s):
	"""Return a sorted list of the contents of a set

	This is intended to be used to iterate over world state.

	Non-strings come before strings and then tuples. Tuples compare
	element-wise as normal.

	This is memoized.

	"""
	if not isinstance(s, Set):
		raise TypeError("sets only")
	s = frozenset(s)
	if s not in _sort_set_memo:
		_sort_set_memo[s] = sorted(s, key=_sort_set_key)
	return _sort_set_memo[s]

def fake_submit(func, *args, **kwargs):
	"""A replacement for `concurrent.futures.Executor.submit` that works in serial

	This is for testing. Use, eg.,
	``@patch.object(executor, 'submit', new=fake_submit)``
	to make normally parallel operations serial.

	"""

	class FakeFuture:

		def __init__(self, func, *args, **kwargs):
			self._func = func
			self._args = args
			self._kwargs = kwargs

		def result(self):
			return self._func(*self._args, **self._kwargs)

	return FakeFuture(func, *args, **kwargs)

class AbstractEngine(ABC):
	"""Parent class to the real Engine as well as EngineProxy.

	Implements serialization and the __getattr__ for stored methods.

	By default, the deserializers will refuse to create LiSE entities.
	If you want them to, use my ``loading`` property to open a ``with``
	block, in which deserialized entities will be created as needed.

	"""

	@cached_property
	def pack(self):
		handlers = {
			self.char_cls:
			lambda char: msgpack.ExtType(MsgpackExtensionType.character.value,
											packer(char.name)),
			self.place_cls:
			lambda place: msgpack.ExtType(
				MsgpackExtensionType.place.value,
				packer([place.character.name, place.name])),
			self.thing_cls:
			lambda thing: msgpack.ExtType(
				MsgpackExtensionType.thing.value,
				packer([thing.character.name, thing.name])),
			self.portal_cls:
			lambda port: msgpack.ExtType(
				MsgpackExtensionType.portal.value,
				packer([
					port.character.name, port.origin.name, port.destination.
					name
				])),
			tuple:
			lambda tup: msgpack.ExtType(MsgpackExtensionType.tuple.value,
										packer(list(tup))),
			frozenset:
			lambda frozs: msgpack.ExtType(MsgpackExtensionType.frozenset.value,
											packer(list(frozs))),
			set:
			lambda s: msgpack.ExtType(MsgpackExtensionType.set.value,
										packer(list(s))),
			FinalRule:
			lambda obj: msgpack.ExtType(MsgpackExtensionType.final_rule.value,
										b""),
			FunctionType:
			lambda func: msgpack.ExtType(
				getattr(MsgpackExtensionType, func.__module__).value,
				packer(func.__name__)),
			MethodType:
			lambda meth: msgpack.ExtType(MsgpackExtensionType.method.value,
											packer(meth.__name__)),
			Exception:
			lambda exc: msgpack.ExtType(
				MsgpackExtensionType.exception.value,
				packer([
					exc.__class__.__name__,
					Traceback(exc.__traceback__).to_dict()
				] + list(exc.args)))
		}

		def pack_handler(obj):
			if isinstance(obj, Exception):
				typ = Exception
			else:
				typ = type(obj)
			if typ in handlers:
				return handlers[typ](obj)
			elif isinstance(obj, Mapping):
				return dict(obj)
			raise TypeError("Can't pack {}".format(typ))

		packer = partial(msgpack.packb,
							default=pack_handler,
							strict_types=True,
							use_bin_type=True)
		return packer

	@cached_property
	def unpack(self):
		charmap = self.character
		char_cls = self.char_cls
		place_cls = self.place_cls
		thing_cls = self.thing_cls
		portal_cls = self.portal_cls
		trigger = self.trigger
		prereq = self.prereq
		action = self.action
		function = self.function
		method = self.method
		excs = {
			# builtin exceptions
			'AssertionError': AssertionError,
			'AttributeError': AttributeError,
			'EOFError': EOFError,
			'FloatingPointError': FloatingPointError,
			'GeneratorExit': GeneratorExit,
			'ImportError': ImportError,
			'IndexError': IndexError,
			'KeyError': KeyError,
			'KeyboardInterrupt': KeyboardInterrupt,
			'MemoryError': MemoryError,
			'NameError': NameError,
			'NotImplementedError': NotImplementedError,
			'OSError': OSError,
			'OverflowError': OverflowError,
			'RecursionError': RecursionError,
			'ReferenceError': ReferenceError,
			'RuntimeError': RuntimeError,
			'StopIteration': StopIteration,
			'IndentationError': IndentationError,
			'TabError': TabError,
			'SystemError': SystemError,
			'SystemExit': SystemExit,
			'TypeError': TypeError,
			'UnboundLocalError': UnboundLocalError,
			'UnicodeError': UnicodeError,
			'UnicodeEncodeError': UnicodeEncodeError,
			'UnicodeDecodeError': UnicodeDecodeError,
			'UnicodeTranslateError': UnicodeTranslateError,
			'ValueError': ValueError,
			'ZeroDivisionError': ZeroDivisionError,
			# LiSE exceptions
			'NonUniqueError': exc.NonUniqueError,
			'AmbiguousAvatarError': exc.AmbiguousAvatarError,
			'AmbiguousUserError': exc.AmbiguousUserError,
			'RulesEngineError': exc.RulesEngineError,
			'RuleError': exc.RuleError,
			'RedundantRuleError': exc.RedundantRuleError,
			'UserFunctionError': exc.UserFunctionError,
			'WorldIntegrityError': exc.WorldIntegrityError,
			'CacheError': exc.CacheError,
			'TravelException': exc.TravelException,
			'OutOfTimelineError': exc.OutOfTimelineError,
			'HistoricKeyError': exc.HistoricKeyError,
			'NotInKeyframeError': exc.NotInKeyframeError
		}

		def unpack_exception(ext):
			data = unpacker(ext)
			if data[0] not in excs:
				return Exception(*data)
			ret = excs[data[0]](*data[2:])
			ret.__traceback__ = Traceback.from_dict(data[1]).to_traceback()
			return ret

		def unpack_char(ext):
			charn = unpacker(ext)
			if charn in charmap:
				return charmap[charn]
			else:
				return char_cls(self, charn, init_rulebooks=False)

		def unpack_place(ext):
			charn, placen = unpacker(ext)
			if charn in charmap:
				char = charmap[charn]
			else:
				return place_cls(char_cls(self, charn), placen)
			placemap = char.place
			if placen in placemap:
				return placemap[placen]
			else:
				return place_cls(char, placen)

		def unpack_thing(ext):
			charn, thingn = unpacker(ext)
			if charn in charmap:
				char = charmap[charn]
			else:
				return thing_cls(char_cls(self, charn), thingn)
			thingmap = char.thing
			if thingn in thingmap:
				return thingmap[thingn]
			else:
				return thing_cls(char, thingn)

		def unpack_portal(ext):
			charn, orign, destn = unpacker(ext)
			if charn in charmap:
				char = charmap[charn]
			else:
				char = char_cls(self, charn)
			portmap = char.portal
			if orign in portmap and destn in portmap[orign]:
				return char.portal[orign][destn]
			else:
				return portal_cls(char, orign, destn)

		handlers = {
			MsgpackExtensionType.character.value:
			unpack_char,
			MsgpackExtensionType.place.value:
			unpack_place,
			MsgpackExtensionType.thing.value:
			unpack_thing,
			MsgpackExtensionType.portal.value:
			unpack_portal,
			MsgpackExtensionType.final_rule.value:
			lambda obj: final_rule,
			MsgpackExtensionType.tuple.value:
			lambda ext: tuple(unpacker(ext)),
			MsgpackExtensionType.frozenset.value:
			lambda ext: frozenset(unpacker(ext)),
			MsgpackExtensionType.set.value:
			lambda ext: set(unpacker(ext)),
			MsgpackExtensionType.trigger.value:
			lambda ext: getattr(trigger, unpacker(ext)),
			MsgpackExtensionType.prereq.value:
			lambda ext: getattr(prereq, unpacker(ext)),
			MsgpackExtensionType.action.value:
			lambda ext: getattr(action, unpacker(ext)),
			MsgpackExtensionType.function.value:
			lambda ext: getattr(function, unpacker(ext)),
			MsgpackExtensionType.method.value:
			lambda ext: getattr(method, unpacker(ext)),
			MsgpackExtensionType.exception.value:
			unpack_exception
		}

		def unpack_handler(code, data):
			if code in handlers:
				return handlers[code](data)
			return msgpack.ExtType(code, data)

		def unpacker(b: bytes):
			the_unpacker = msgpack.Unpacker(ext_hook=unpack_handler,
											raw=False,
											strict_map_key=False)
			the_unpacker.feed(b)
			# Deliberately only returning the initial item;
			# others are likely to be null bytes as a result of the
			# way browsers work, and anyway if you really want more
			# you can just pack a list
			return the_unpacker.unpack()

		return unpacker

	@property
	def initial_turn(self):
		"""The first turn of the current branch"""
		return self._branches[self.branch][1]

	@property
	def final_turn(self):
		"""The last turn of the current branch"""
		return self._branches[self.branch][3]

	def coin_flip(self) -> bool:
		"""Return True or False with equal probability."""
		return self.choice((True, False))

	def die_roll(self, d) -> int:
		"""Roll a die with ``d`` faces. Return the result."""
		return self.randint(1, d)

	def dice(self, n, d) -> Iterable[int]:
		"""Roll ``n`` dice with ``d`` faces, and yield the results.

		This is an iterator. You'll get the result of each die in
		succession.

		"""
		for i in range(0, n):
			yield self.die_roll(d)

	def dice_check(self,
					n: int,
					d: int,
					target: int,
					comparator: Union[str, Callable] = '<=') -> bool:
		"""Roll ``n`` dice with ``d`` sides, sum them, and compare

		If ``comparator`` is provided, use it instead of the default <=.
		You may use a string like '<' or '>='.

		"""
		from operator import gt, lt, ge, le, eq, ne

		comps: Dict[str, Callable] = {
			'>': gt,
			'<': lt,
			'>=': ge,
			'<=': le,
			'=': eq,
			'==': eq,
			'!=': ne
		}
		if not callable(comparator):
			comparator = comps[comparator]
		return comparator(sum(self.dice(n, d)), target)

	def percent_chance(self, pct: int) -> bool:
		"""Return True or False with a given percentile probability

		Values not between 0 and 100 are treated as though they
		were 0 or 100, whichever is nearer.

		"""
		if pct <= 0:
			return False
		if pct >= 100:
			return True
		return pct > self.randint(0, 99)

	betavariate = get_rando('_rando.betavariate')
	choice = get_rando('_rando.choice')
	expovariate = get_rando('_rando.expovariate')
	gammavariate = get_rando('_rando.gammavariate')
	gauss = get_rando('_rando.gauss')
	getrandbits = get_rando('_rando.getrandbits')
	lognormvariate = get_rando('_rando.lognormvariate')
	normalvariate = get_rando('_rando.normalvariate')
	paretovariate = get_rando('_rando.paretovariate')
	randint = get_rando('_rando.randint')
	random = get_rando('_rando.random')
	randrange = get_rando('_rando.randrange')
	sample = get_rando('_rando.sample')
	shuffle = get_rando('_rando.shuffle')
	triangular = get_rando('_rando.triangular')
	uniform = get_rando('_rando.uniform')
	vonmisesvariate = get_rando('_rando.vonmisesvariate')
	weibullvariate = get_rando('_rando.weibullvariate')

class SpecialMappingDescriptor:

	def __init__(self, mapclsname):
		self.mapps = {}
		self.mapclsname = mapclsname

	def __get__(self, instance, owner):
		attname = "_" + self.mapclsname
		if not hasattr(instance, attname):
			mappcls = getattr(instance, self.mapclsname)
			setattr(instance, attname, mappcls(instance))
		return getattr(instance, attname)

	def __set__(self, instance, value):
		attname = "_" + self.mapclsname
		if not hasattr(instance, attname):
			mappcls = getattr(instance, self.mapclsname)
			setattr(instance, attname, mappcls(instance))
		it = getattr(instance, attname)
		it.clear()
		it.update(value)

class AbstractCharacter(Mapping):
	"""The Character API, with all requisite mappings and graph generators.

	Mappings resemble those of a NetworkX digraph:

	* ``thing`` and ``place`` are subsets of ``node``
	* ``edge``, ``adj``, and ``succ`` are aliases of ``portal``
	* ``pred`` is an alias to ``preportal``
	* ``stat`` is a dict-like mapping of data that changes over game-time,
	to be used in place of graph attributes

	"""
	engine = getatt('db')
	no_unwrap = True
	name: Hashable
	db: AbstractEngine

	@staticmethod
	def is_directed():
		return True

	@abstractmethod
	def add_place(self, name, **kwargs):
		pass

	def add_node(self, name, **kwargs):
		self.add_place(name, **kwargs)

	@abstractmethod
	def add_places_from(self, seq, **attrs):
		pass

	def add_nodes_from(self, seq, **attrs):
		self.add_places_from(seq, **attrs)

	def new_place(self, name, **kwargs):
		"""Add a Place and return it.

		If there's already a Place by that name, put a number on the end.

		"""
		if name not in self.node:
			self.add_place(name, **kwargs)
			return self.place[name]
		if isinstance(name, str):
			n = 0
			while name + str(n) in self.node:
				n += 1
			self.add_place(name + str(n), **kwargs)
			return self.place[name]
		raise KeyError("Already have a node named {}".format(name))

	def new_node(self, name, **kwargs):
		return self.new_place(name, **kwargs)

	@abstractmethod
	def add_thing(self, name, location, **kwargs):
		pass

	@abstractmethod
	def add_things_from(self, seq, **attrs):
		pass

	def new_thing(self, name, location, **kwargs):
		"""Add a Thing and return it.

		If there's already a Thing by that name, put a number on the end.

		"""
		if name not in self.node:
			self.add_thing(name, location, **kwargs)
			return self.thing[name]
		if isinstance(name, str):
			if name in self.node:
				n = 0
				while name + str(n) in self.node:
					n += 1
				name = name + str(n)
			self.add_thing(name, location, **kwargs)
			return self.thing[name]
		raise KeyError("Already have a thing named {}".format(name))

	@abstractmethod
	def thing2place(self, name):
		pass

	@abstractmethod
	def place2thing(self, name, location):
		pass

	@abstractmethod
	def add_portal(self, orig, dest, **kwargs):
		pass

	def add_edge(self, orig, dest, **kwargs):
		self.add_portal(orig, dest, **kwargs)

	def new_portal(self, orig, dest, **kwargs):
		self.add_portal(orig, dest, **kwargs)
		return self.portal[orig][dest]

	@abstractmethod
	def add_portals_from(self, seq, **attrs):
		pass

	def add_edges_from(self, seq, **attrs):
		self.add_portals_from(seq, **attrs)

	@abstractmethod
	def remove_portal(self, origin, destination):
		pass

	def remove_portals_from(self, seq):
		for orig, dest in seq:
			del self.portal[orig][dest]

	def remove_edges_from(self, seq):
		self.remove_portals_from(seq)

	@abstractmethod
	def remove_place(self, place):
		pass

	def remove_places_from(self, seq):
		for place in seq:
			self.remove_place(place)

	@abstractmethod
	def remove_thing(self, thing):
		pass

	def remove_things_from(self, seq):
		for thing in seq:
			self.remove_thing(thing)

	@abstractmethod
	def remove_node(self, node):
		pass

	def remove_nodes_from(self, seq):
		for node in seq:
			self.remove_node(node)

	@abstractmethod
	def add_unit(self, a, b=None):
		pass

	@abstractmethod
	def remove_unit(self, a, b=None):
		pass

	def __eq__(self, other):
		return isinstance(other, AbstractCharacter) and self.name == other.name

	def __iter__(self):
		return iter(self.node)

	def __len__(self):
		return len(self.node)

	def __bool__(self):
		try:
			return self.name in self.db.character
		except AttributeError:
			return False  # we can't "really exist" when we've no engine

	def __contains__(self, k):
		return k in self.node

	def __getitem__(self, k):
		return self.adj[k]

	thing = SpecialMappingDescriptor('ThingMapping')
	place = SpecialMappingDescriptor('PlaceMapping')
	node = nodes = _node = SpecialMappingDescriptor('ThingPlaceMapping')
	portal = adj = succ = edge = _adj = _succ = SpecialMappingDescriptor(
		'PortalSuccessorsMapping')
	preportal = pred = _pred = SpecialMappingDescriptor(
		'PortalPredecessorsMapping')
	unit = SpecialMappingDescriptor('UnitGraphMapping')
	stat = getatt('graph')

	def historical(self, stat):
		from .query import StatusAlias
		return StatusAlias(entity=self.stat, stat=stat)

	def do(self, func, *args, **kwargs):
		"""Apply the function to myself, and return myself.

		Look up the function in the method store if needed. Pass it any
		arguments given, keyword or positional.

		Useful chiefly when chaining.

		"""
		if not callable(func):
			func = getattr(self.engine.method, func)
		func(self, *args, **kwargs)
		return self

	def copy_from(self, g):
		"""Copy all nodes and edges from the given graph into this.

		Return myself.

		"""
		renamed = {}
		for k in g.nodes:
			ok = k
			if k in self.place:
				n = 0
				while k in self.place:
					k = ok + (n, ) if isinstance(ok, tuple) else (ok, n)
					n += 1
			renamed[ok] = k
			self.place[k] = g.nodes[k]
		if type(g) is nx.MultiDiGraph:
			g = nx.DiGraph(g)
		elif type(g) is nx.MultiGraph:
			g = nx.Graph(g)
		if type(g) is nx.DiGraph:
			for u, v in g.edges:
				self.edge[renamed[u]][renamed[v]] = g.adj[u][v]
		else:
			assert type(g) is nx.Graph
			for u, v, d in g.edges.data():
				self.add_portal(renamed[u], renamed[v], symmetrical=True, **d)
		return self

	def become(self, g):
		"""Erase all my nodes and edges. Replace them with a copy of the graph
		provided.

		Return myself.

		"""
		self.clear()
		self.place.update(g.nodes)
		self.adj.update(g.adj)
		return self

	def clear(self):
		self.node.clear()
		self.portal.clear()
		self.stat.clear()

	def _lookup_comparator(self, comparator):
		if callable(comparator):
			return comparator
		ops = {'ge': ge, 'gt': gt, 'le': le, 'lt': lt, 'eq': eq}
		if comparator in ops:
			return ops[comparator]
		return getattr(self.engine.function, comparator)

	def cull_nodes(self, stat, threshold=0.5, comparator=ge):
		"""Delete nodes whose stat >= ``threshold`` (default 0.5).

		Optional argument ``comparator`` will replace >= as the test
		for whether to cull. You can use the name of a stored function.

		"""
		comparator = self._lookup_comparator(comparator)
		dead = [
			name for name, node in self.node.items()
			if stat in node and comparator(node[stat], threshold)
		]
		self.remove_nodes_from(dead)
		return self

	def cull_portals(self, stat, threshold=0.5, comparator=ge):
		"""Delete portals whose stat >= ``threshold`` (default 0.5).

		Optional argument ``comparator`` will replace >= as the test
		for whether to cull. You can use the name of a stored function.

		"""
		comparator = self._lookup_comparator(comparator)
		dead = []
		for u in self.portal:
			for v in self.portal[u]:
				if stat in self.portal[u][v] and comparator(
					self.portal[u][v][stat], threshold):
					dead.append((u, v))
		self.remove_edges_from(dead)
		return self

	cull_edges = cull_portals

def normalize_layout(l):
	"""Make sure all the spots in a layout are where you can click.

	Returns a copy of the layout with all spot coordinates are
	normalized to within (0.0, 0.98).

	"""
	xs = []
	ys = []
	ks = []
	for (k, (x, y)) in l.items():
		xs.append(x)
		ys.append(y)
		ks.append(k)
	minx = np.min(xs)
	maxx = np.max(xs)
	if maxx == minx:
		xnorm = np.array([0.5] * len(xs))
	else:
		xco = 0.98 / (maxx - minx)
		xnorm = np.multiply(np.subtract(xs, [minx] * len(xs)), xco)
	miny = np.min(ys)
	maxy = np.max(ys)
	if miny == maxy:
		ynorm = np.array([0.5] * len(ys))
	else:
		yco = 0.98 / (maxy - miny)
		ynorm = np.multiply(np.subtract(ys, [miny] * len(ys)), yco)
	return dict(zip(ks, zip(map(float, xnorm), map(float, ynorm))))


import pickle
from argparse import ArgumentParser
from freegroup.sampling import normal_closure_conjugation as normal_closure, random_order_commutant
from itertools import islice
from iteration_utilities import unique_everseen

parser = ArgumentParser(description='Generate dataset of elements from symmetric commutant')
parser.add_argument('generators_number', type=int, help='number of generators (x, y, z, ...)')
parser.add_argument('max_length', type=int, help = 'maximal length of generated words')
parser.add_argument('part_max_length', type=int, help='maximal length of word from one normal closure (generated to be included in result')
parser.add_argument('max_number_multipliers', type=int, help='maximal number of symmetric commutant multipliers')
parser.add_argument('size', type=int, help='desired number of words in the dataset')
args = parser.parse_args()

generators = [[i] for i in range(1, args.generators_number + 1)] + \
    [list(range(1, args.generators_number + 1))]

closures = [normal_closure(g, generators_number=args.generators_number, max_length=args.part_max_length) for g in generators]

g = random_order_commutant(closures)

g = filter(lambda x: len(x) < args.max_length, g)
dataset = list(islice(unique_everseen(g, key = tuple), args.size))

print('average length =', int(sum(map(len, dataset)) / len(dataset)))
real_max_length = max(map(len, dataset))
print('max length =', real_max_length)

with open(f"datasets/symcom_n={args.generators_number}_l={real_max_length}.pkl", "wb") as file:
    pickle.dump(dataset, file)


import streamlit as st
import pandas as pd
from spellchecker import SpellChecker

# Load the cleaned dataset
df2 = pd.read_csv("C:/Users/Mi/Downloads/Job Analytics/finalcleandata.csv")

# Fill missing skill columns with empty strings and create lowercase versions for searching
df2['Skills1'] = df2['Skills1'].fillna("")
df2["lower_skills1"] = df2['Skills1'].str.lower()
df2["lower_skills2"] = df2['Skills2'].str.lower()
df2["lower_skills3"] = df2['Skills3'].str.lower()
df2["lower_skills4"] = df2['Skills4'].str.lower()
df2["lower_skills5"] = df2['Skills5'].str.lower()
df2["lower_skills6"] = df2['Skills6'].str.lower()
df2["lower_skills7"] = df2['Skills7'].str.lower()

# Streamlit configuration
st.set_page_config(
    page_title="Job Analytics",
    page_icon="ðŸ’¼",
)

# Frontend header
html_temp = """

Job Analytics

"""
st.markdown(html_temp, unsafe_allow_html=True)

# Description of the search feature
st.markdown("
 Our search feature displays the most prevalent experience level, top workplace, and popular classes for a particular skill, along with the total number of jobs related to that skill.
", unsafe_allow_html=True)

# Load skills from a dictionary
with open('C:/Users/Mi/Downloads/Job Analytics/dictionary.txt') as f:
    skills = f.read().splitlines()

# Create a case-insensitive spell checker
spell = SpellChecker(language=None, case_sensitive=False)
spell.word_frequency.load_words(skills)

# Text input for skill search
text_search = st.text_input("**Search Skills**", value="")

if text_search:
    corrected_input = spell.correction(text_search)
    st.write(f'Searching for jobs related to: {corrected_input}')

    # Create masks for skills in different columns
    m1 = df2["lower_skills1"].str.contains(corrected_input)
    m2 = df2["lower_skills2"].str.contains(corrected_input)
    m3 = df2["lower_skills3"].str.contains(corrected_input)
    m4 = df2["lower_skills4"].str.contains(corrected_input)
    m5 = df2["lower_skills5"].str.contains(corrected_input)
    m6 = df2["lower_skills6"].str.contains(corrected_input)
    m7 = df2["lower_skills7"].str.contains(corrected_input)

    # Combine masks to get the search results
    df_search = df2[m1 | m2 | m3 | m4 | m5 | m6 | m7]
    df_search = df_search.reset_index(drop=True)
    df_search.index += 1

    if corrected_input:
        col1, col2 = st.columns(2)
        with col1:
            st.markdown('
Most Common Experience Level :
', unsafe_allow_html=True)
            st.markdown('
Most Common Workplace :
', unsafe_allow_html=True)
            st.markdown('
Most Common Classes :
', unsafe_allow_html=True)
            st.markdown('
Total Number of Jobs Available :
', unsafe_allow_html=True)
        with col2:
            exp = df_search['Experience Category'].mode()[0]
            st.markdown(f'
{exp}
', unsafe_allow_html=True)

            loc = df_search['Locations'].mode()[0]
            st.markdown(f'
{loc}
', unsafe_allow_html=True)

            cls = df_search['Cluster'].mode()[0]
            st.markdown(f'
{cls}
', unsafe_allow_html=True)

            num_jobs = str(len(df_search))
            st.markdown(f'
{num_jobs}
', unsafe_allow_html=True)

# Display job details
st.markdown(
    """

    """,
    unsafe_allow_html=True,
)

if st.button("Job Details >>"):
    data = pd.concat([df_search['Company'], df_search['Designation'], df_search['Locations'].rename("Workplace"),df_search['HR_Name'].rename("HR Name"),df_search['Experience'],df_search['Link'].rename("Apply Link")], axis=1)
    st.write(data)

    # Card style for displaying job details
    card_style = """

    """
    st.markdown(card_style, unsafe_allow_html=True)

    # Loop through records and create job cards
    for index, row in data.iterrows():
        card = """

Company Name  :  {}

Designation    :  {}

Workplace      :  {}

HR Name        :  {}

Experience     :  {}

            Click Here to Apply

        """.format(row['Company'], row['Designation'], row['Workplace'], row['HR Name'], row['Experience'], link=row['Apply Link'])

        st.markdown(card, unsafe_allow_html=True)