from functools import wraps
import re
from collections import defaultdict
from datetime import datetime, timedelta, timezone
import humanize
import simplejson as json
from dateutil.tz import tzutc

from flask import Blueprint, g, redirect, request, url_for, current_app, jsonify
from flask_login import current_user, login_required, logout_user
from flask_themes2 import render_theme_template
from sdc.crypto.encrypter import encrypt
from jwcrypto.common import base64url_decode

from structlog import get_logger

from app.globals import get_session_store, get_completeness
from app.data_model.answer_store import Answer, AnswerStore
from app.data_model.app_models import SubmittedResponse
from app.globals import get_answer_store, get_completed_blocks, get_metadata, get_questionnaire_store
from app.helpers.form_helper import post_form_for_location
from app.helpers.path_finder_helper import path_finder, full_routing_path_required
from app.helpers.schema_helpers import with_schema
from app.helpers.session_helpers import with_answer_store, with_metadata
from app.helpers.template_helper import (with_session_timeout, with_metadata_context, with_analytics,
                                         with_questionnaire_url_prefix, with_legal_basis, render_template)

from app.questionnaire.location import Location
from app.questionnaire.navigation import Navigation
from app.questionnaire.path_finder import PathFinder
from app.questionnaire.router import Router
from app.questionnaire.rules import get_answer_ids_on_routing_path
from app.questionnaire.rules import evaluate_skip_conditions

from app.keys import KEY_PURPOSE_SUBMISSION
from app.storage import data_access
from app.storage.storage_encryption import StorageEncryption
from app.submitter.converter import convert_answers
from app.submitter.submission_failed import SubmissionFailedException
from app.templating.metadata_context import build_metadata_context_for_survey_completed
from app.templating.schema_context import build_schema_context
from app.templating.summary_context import build_summary_rendering_context
from app.templating.template_renderer import renderer, TemplateRenderer
from app.templating.view_context import build_view_context
from app.templating.utils import get_question_title

from app.utilities.schema import load_schema_from_session_data
from app.views.errors import MultipleSurveyError
from app.authentication.no_token_exception import NoTokenException

END_BLOCKS = 'Summary', 'Confirmation'

logger = get_logger()

questionnaire_blueprint = Blueprint(name='questionnaire',
                                    import_name=__name__,
                                    url_prefix='/questionnaire/<eq_id>/<form_type>/<collection_id>/')

post_submission_blueprint = Blueprint(name='post_submission',
                                      import_name=__name__,
                                      url_prefix='/questionnaire/<eq_id>/<form_type>/')

@questionnaire_blueprint.before_request
def before_questionnaire_request():
    metadata = get_metadata(current_user)
    if not metadata:
        raise NoTokenException(401)

    logger.bind(tx_id=metadata['tx_id'])

    values = request.view_args
    logger.bind(eq_id=values['eq_id'], form_type=values['form_type'],
                ce_id=values['collection_id'])
    logger.info('questionnaire request', method=request.method, url_path=request.full_path)

    _check_same_survey(url_eq_id=values['eq_id'],
                       url_form_type=values['form_type'],
                       url_collection_id=values['collection_id'],
                       session_eq_id=metadata['eq_id'],
                       session_form_type=metadata['form_type'],
                       session_collection_id=metadata['collection_exercise_sid'])

    session_data = get_session_store().session_data
    g.schema = load_schema_from_session_data(session_data)

@post_submission_blueprint.before_request
def before_post_submission_request():
    session = get_session_store()
    if not session or not session.session_data:
        raise NoTokenException(401)

    session_data = session.session_data
    g.schema = load_schema_from_session_data(session_data)

    logger.bind(tx_id=session_data.tx_id)

    values = request.view_args
    logger.bind(eq_id=values['eq_id'], form_type=values['form_type'])
    logger.info('questionnaire request', method=request.method, url_path=request.full_path)

    _check_same_survey(url_eq_id=values['eq_id'],
                       url_form_type=values['form_type'],
                       url_collection_id='',
                       session_eq_id=session_data.eq_id,
                       session_form_type=session_data.form_type,
                       session_collection_id='')

@questionnaire_blueprint.after_request
def add_cache_control(response):
    response.cache_control.no_cache = True

    return response

def save_questionnaire_store(func):
    @wraps(func)
    def save_questionnaire_store_wrapper(*args, **kwargs):
        response = func(*args, **kwargs)
        if not current_user.is_anonymous:
            questionnaire_store = get_questionnaire_store(current_user.user_id, current_user.user_ik)

            questionnaire_store.add_or_update()

        return response

    return save_questionnaire_store_wrapper

@questionnaire_blueprint.route('<group_id>/<int:group_instance>/<block_id>', methods=['GET'])
@login_required
@with_answer_store
@with_metadata
@with_schema
@full_routing_path_required
def get_block(routing_path, schema, metadata, answer_store, eq_id, form_type, collection_id, group_id,  # pylint: disable=too-many-locals
              group_instance, block_id):
    current_location = Location(group_id, group_instance, block_id)
    completeness = get_completeness(current_user)
    router = Router(schema, routing_path, completeness, current_location)

    if not router.can_access_location():
        next_location = router.get_next_location()
        return _redirect_to_location(collection_id, eq_id, form_type, next_location)

    block = _get_block_json(current_location, schema, answer_store, metadata)
    context = _get_context(routing_path, block, current_location, schema)

    return _render_page(block['type'], context, current_location, schema, answer_store, metadata, routing_path)

@questionnaire_blueprint.route('<group_id>/<int:group_instance>/<block_id>', methods=['POST'])
@login_required
@with_answer_store
@with_metadata
@with_schema
@full_routing_path_required
def post_block(routing_path, schema, metadata, answer_store, eq_id, form_type, collection_id, group_id,  # pylint: disable=too-many-locals
               group_instance, block_id):
    current_location = Location(group_id, group_instance, block_id)
    completeness = get_completeness(current_user)
    router = Router(schema, routing_path, completeness, current_location)

    if not router.can_access_location():
        next_location = router.get_next_location()
        return _redirect_to_location(collection_id, eq_id, form_type, next_location)

    block = _get_block_json(current_location, schema, answer_store, metadata)

    schema_context = _get_schema_context(routing_path, current_location.group_instance, metadata, answer_store, schema)

    rendered_block = renderer.render(block, **schema_context)

    form = _generate_wtf_form(request.form, rendered_block, current_location, schema)

    if 'action[save_sign_out]' in request.form:
        return _save_sign_out(routing_path, current_location, form, schema, answer_store, metadata)

    if form.validate():
        _set_started_at_metadata_if_required(form, metadata)
        _update_questionnaire_store(current_location, form, schema)
        next_location = path_finder.get_next_location(current_location=current_location)

        if _is_end_of_questionnaire(block, next_location):
            return submit_answers(routing_path, eq_id, form_type, schema)

        return redirect(_next_location_url(next_location))

    context = build_view_context(block['type'], metadata, schema, answer_store, schema_context, rendered_block, current_location, form)

    return _render_page(block['type'], context, current_location, schema, answer_store, metadata, routing_path)

@questionnaire_blueprint.route('<group_id>/0/household-composition', methods=['POST'])
@login_required
@with_answer_store
@with_metadata
@with_schema
@full_routing_path_required
def post_household_composition(routing_path, schema, metadata, answer_store, **kwargs):
    group_id = kwargs['group_id']

    if _household_answers_changed(answer_store, schema):
        _remove_repeating_on_household_answers(answer_store, schema)

    disable_mandatory = any(x in request.form for x in ['action[add_answer]', 'action[remove_answer]', 'action[save_sign_out]'])

    current_location = Location(group_id, 0, 'household-composition')

    block = _get_block_json(current_location, schema, answer_store, metadata)

    form = post_form_for_location(schema, block, current_location, answer_store, metadata,
                                  request.form, disable_mandatory=disable_mandatory)

    form.validate()  # call validate here to keep errors in the form object on the context
    context = _get_context(routing_path, block, current_location, schema, form)

    if 'action[add_answer]' in request.form:
        form.household.append_entry()

        return _render_page(block['type'], context, current_location, schema, answer_store, metadata, routing_path)

    if 'action[remove_answer]' in request.form:
        index_to_remove = int(request.form.get('action[remove_answer]'))
        form.remove_person(index_to_remove)

        return _render_page(block['type'], context, current_location, schema, answer_store, metadata, routing_path)

    if 'action[save_sign_out]' in request.form:
        response = _save_sign_out(routing_path, current_location, form, schema, answer_store, metadata)
        remove_empty_household_members_from_answer_store(answer_store, schema)

        return response

    if form.validate():
        questionnaire_store = get_questionnaire_store(current_user.user_id, current_user.user_ik)
        update_questionnaire_store_with_answer_data(questionnaire_store, current_location, form.serialise(), schema)

        metadata = get_metadata(current_user)
        next_location = path_finder.get_next_location(current_location=current_location)

        return redirect(next_location.url(metadata))

    return _render_page(block['type'], context, current_location, schema, answer_store, metadata, routing_path)

@post_submission_blueprint.route('thank-you', methods=['GET'])
@login_required
@with_metadata
@with_schema
def get_thank_you(schema, metadata, eq_id, form_type):  # pylint: disable=unused-argument
    session_data = get_session_store().session_data
    completeness = get_completeness(current_user)

    if session_data.submitted_time:
        metadata_context = build_metadata_context_for_survey_completed(session_data)

        view_submission_url = None
        view_submission_duration = 0
        if _is_submission_viewable(schema.json, session_data.submitted_time):
            view_submission_url = url_for('.get_view_submission', eq_id=eq_id, form_type=form_type)
            view_submission_duration = humanize.naturaldelta(timedelta(seconds=schema.json['view_submitted_response']['duration']))

        return render_theme_template(schema.json['theme'],
                                     template_name='thank-you.html',
                                     metadata=metadata_context,
                                     analytics_ua_id=current_app.config['EQ_UA_ID'],
                                     survey_id=schema.json['survey_id'],
                                     survey_title=TemplateRenderer.safe_content(schema.json['title']),
                                     is_view_submitted_response_enabled=is_view_submitted_response_enabled(schema.json),
                                     view_submission_url=view_submission_url,
                                     view_submission_duration=view_submission_duration)

    routing_path = path_finder.get_full_routing_path()

    collection_id = metadata['collection_exercise_sid']

    router = Router(schema, routing_path, completeness)
    next_location = router.get_next_location()

    return _redirect_to_location(collection_id, metadata.get('eq_id'), metadata.get('form_type'), next_location)

@post_submission_blueprint.route('view-submission', methods=['GET'])
@login_required
@with_schema
def get_view_submission(schema, eq_id, form_type):  # pylint: disable=unused-argument

    session_data = get_session_store().session_data

    if _is_submission_viewable(schema.json, session_data.submitted_time):
        submitted_data = data_access.get_by_key(SubmittedResponse, session_data.tx_id)

        if submitted_data:

            metadata_context = build_metadata_context_for_survey_completed(session_data)

            pepper = current_app.eq['secret_store'].get_secret_by_name('EQ_SERVER_SIDE_STORAGE_ENCRYPTION_USER_PEPPER')

            encrypter = StorageEncryption(current_user.user_id, current_user.user_ik, pepper)
            submitted_data = encrypter.decrypt_data(submitted_data.data)

            # for backwards compatibility
            # submitted data used to be base64 encoded before encryption
            try:
                submitted_data = base64url_decode(submitted_data.decode()).decode()
            except ValueError:
                pass

            submitted_data = json.loads(submitted_data)
            answer_store = AnswerStore(existing_answers=submitted_data.get('answers'))

            metadata = submitted_data.get('metadata')

            routing_path = PathFinder(schema, answer_store, metadata, []).get_full_routing_path()

            schema_context = _get_schema_context(routing_path, 0, metadata, answer_store, schema)
            rendered_schema = renderer.render(schema.json, **schema_context)
            summary_rendered_context = build_summary_rendering_context(schema, rendered_schema['sections'], answer_store, metadata)

            context = {
                'summary': {
                    'groups': summary_rendered_context,
                    'answers_are_editable': False,
                    'is_view_submission_response_enabled': is_view_submitted_response_enabled(schema.json),
                },
                'variables': None,
            }

            return render_theme_template(schema.json['theme'],
                                         template_name='view-submission.html',
                                         metadata=metadata_context,
                                         analytics_ua_id=current_app.config['EQ_UA_ID'],
                                         survey_id=schema.json['survey_id'],
                                         survey_title=TemplateRenderer.safe_content(schema.json['title']),
                                         content=context)

    return redirect(url_for('post_submission.get_thank_you', eq_id=eq_id, form_type=form_type))

def _set_started_at_metadata_if_required(form, metadata):
    questionnaire_store = get_questionnaire_store(current_user.user_id, current_user.user_ik)
    if not questionnaire_store.answer_store.answers and len(form.data) > 1:
        started_at = datetime.now(timezone.utc).isoformat()
        logger.info('first answer about to be stored. writing started_at time to metadata',
                    started_at=started_at)
        metadata['started_at'] = started_at

def _render_page(block_type, context, current_location, schema, answer_store, metadata, routing_path):
    if request_wants_json():
        return jsonify(context)

    return _build_template(
        current_location,
        context,
        block_type,
        schema,
        answer_store,
        metadata,
        routing_path=routing_path)

def _generate_wtf_form(form, block, location, schema):
    disable_mandatory = 'action[save_sign_out]' in form

    wtf_form = post_form_for_location(
        schema,
        block,
        location,
        get_answer_store(current_user),
        get_metadata(current_user),
        request.form,
        disable_mandatory)

    return wtf_form

def _next_location_url(location):
    metadata = get_metadata(current_user)
    return location.url(metadata)

def _is_end_of_questionnaire(block, next_location):
    return (
        block['type'] in END_BLOCKS and
        next_location is None
    )

def submit_answers(routing_path, eq_id, form_type, schema):
    metadata = get_metadata(current_user)
    answer_store = get_answer_store(current_user)

    message = json.dumps(convert_answers(
        metadata,
        schema,
        answer_store,
        routing_path,
    ))

    encrypted_message = encrypt(message, current_app.eq['key_store'], KEY_PURPOSE_SUBMISSION)
    sent = current_app.eq['submitter'].send_message(
        encrypted_message,
        current_app.config['EQ_RABBITMQ_QUEUE_NAME'],
        metadata['tx_id'],
    )

    if not sent:
        raise SubmissionFailedException()

    submitted_time = datetime.utcnow()

    _store_submitted_time_in_session(submitted_time)

    if is_view_submitted_response_enabled(schema.json):
        _store_viewable_submission(answer_store.answers, metadata, submitted_time)

    get_questionnaire_store(current_user.user_id, current_user.user_ik).delete()

    return redirect(url_for('post_submission.get_thank_you', eq_id=eq_id, form_type=form_type))

def _store_submitted_time_in_session(submitted_time):
    session_store = get_session_store()
    session_data = session_store.session_data
    session_data.submitted_time = submitted_time.isoformat()
    session_store.save()

def _store_viewable_submission(answers, metadata, submitted_time):
    pepper = current_app.eq['secret_store'].get_secret_by_name('EQ_SERVER_SIDE_STORAGE_ENCRYPTION_USER_PEPPER')
    encrypter = StorageEncryption(current_user.user_id, current_user.user_ik, pepper)
    encrypted_data = encrypter.encrypt_data(
        {
            'answers': answers,
            'metadata': metadata,
        },
    )

    valid_until = submitted_time + timedelta(seconds=g.schema.json['view_submitted_response']['duration'])

    item = SubmittedResponse(
        tx_id=metadata['tx_id'],
        data=encrypted_data,
        valid_until=valid_until.replace(tzinfo=tzutc()),
    )

    data_access.put(item)

def is_view_submitted_response_enabled(schema):
    view_submitted_response = schema.get('view_submitted_response')
    if view_submitted_response:
        return view_submitted_response['enabled']

    return False

def _is_submission_viewable(schema, submitted_time):
    if is_view_submitted_response_enabled(schema) and submitted_time:
        submitted_time = datetime.strptime(submitted_time, '%Y-%m-%dT%H:%M:%S.%f')
        submission_valid_until = submitted_time + timedelta(seconds=schema['view_submitted_response']['duration'])
        return submission_valid_until > datetime.utcnow()

    return False

def _save_sign_out(routing_path, current_location, form, schema, answer_store, metadata):
    questionnaire_store = get_questionnaire_store(current_user.user_id, current_user.user_ik)

    block = _get_block_json(current_location, schema, answer_store, metadata)

    if form.validate():
        _update_questionnaire_store(current_location, form, schema)

        if current_location in questionnaire_store.completed_blocks:
            questionnaire_store.remove_completed_blocks(location=current_location)
            questionnaire_store.add_or_update()

        logout_user()

        return redirect(url_for('session.get_sign_out'))

    context = _get_context(routing_path, block, current_location, schema, form)
    return _render_page(block['type'], context, current_location, schema, answer_store, metadata, routing_path)

def _household_answers_changed(answer_store, schema):
    answer_ids = schema.get_answer_ids_for_block('household-composition')
    household_answers = answer_store.filter(answer_ids)
    stripped_form = request.form.copy()
    del stripped_form['csrf_token']
    remove = [k for k in stripped_form if 'action[' in k]
    for k in remove:
        del stripped_form[k]
    if household_answers.count() != len(stripped_form):
        return True
    for answer in request.form:
        answer_id, answer_index = extract_answer_id_and_instance(answer)

        try:
            stored_answer = household_answers.filter(
                answer_ids=[answer_id],
                answer_instance=answer_index)[0]
        except IndexError:
            stored_answer = None

        if stored_answer and (stored_answer['value'] or '') != request.form[answer]:
            return True

    return False

def _remove_repeating_on_household_answers(answer_store, schema):
    answer_ids = schema.get_answer_ids_for_block('household-composition')
    answer_store.remove(answer_ids=answer_ids)
    questionnaire_store = get_questionnaire_store(
        current_user.user_id,
        current_user.user_ik,
    )

    for answer in schema.get_answers_that_repeat_in_block('household-composition'):
        groups_to_delete = schema.get_groups_that_repeat_with_answer_id(answer['id'])
        for group in groups_to_delete:
            answer_ids = schema.get_answer_ids_for_group(group['id'])
            answer_store.remove(answer_ids=answer_ids)
            questionnaire_store.completed_blocks[:] = [b for b in questionnaire_store.completed_blocks if
                                                       b.group_id != group['id']]

def remove_empty_household_members_from_answer_store(answer_store, schema):
    answer_ids = schema.get_answer_ids_for_block('household-composition')
    household_answers = answer_store.filter(answer_ids=answer_ids)
    household_member_name = defaultdict(list)
    for household_answer in household_answers:
        if household_answer['answer_id'] == 'first-name' or household_answer['answer_id'] == 'last-name':
            household_member_name[household_answer['answer_instance']].append(household_answer['value'])

    to_be_removed = []
    for k, v in household_member_name.items():
        name_value = ''.join(v).strip()
        if not name_value:
            to_be_removed.append(k)

    for instance_to_remove in to_be_removed:
        answer_store.remove(answer_ids=answer_ids, answer_instance=instance_to_remove)

def _update_questionnaire_store(current_location, form, schema):
    questionnaire_store = get_questionnaire_store(current_user.user_id, current_user.user_ik)
    if current_location.block_id in ['relationships', 'household-relationships']:
        update_questionnaire_store_with_answer_data(questionnaire_store, current_location,
                                                    form.serialise(), schema)
    else:
        update_questionnaire_store_with_form_data(questionnaire_store, current_location, form.data, schema)

@save_questionnaire_store
def update_questionnaire_store_with_form_data(questionnaire_store, location, answer_dict, schema):

    survey_answer_ids = schema.get_answer_ids_for_block(location.block_id)

    for answer_id, answer_value in answer_dict.items():

        # If answer is not answered then check for a schema specified default
        if answer_value is None:
            answer_value = schema.get_answer(answer_id).get('default')

        if answer_id in survey_answer_ids or location.block_id == 'household-composition':
            if answer_value is not None:
                answer = Answer(answer_id=answer_id,
                                value=answer_value,
                                group_instance=location.group_instance)

                latest_answer_store_hash = questionnaire_store.answer_store.get_hash()
                questionnaire_store.answer_store.add_or_update(answer)
                if latest_answer_store_hash != questionnaire_store.answer_store.get_hash() and schema.dependencies[answer_id]:
                    _remove_dependent_answers_from_completed_blocks(answer_id, location.group_instance, questionnaire_store, schema)
            else:
                _remove_answer_from_questionnaire_store(
                    answer_id,
                    questionnaire_store,
                    group_instance=location.group_instance)

    if location not in questionnaire_store.completed_blocks:
        questionnaire_store.completed_blocks.append(location)

def _remove_dependent_answers_from_completed_blocks(answer_id, group_instance, questionnaire_store, schema):
    """
    Gets a list of answers ids that are dependent on the answer_id passed in.
    Then for each dependent answer it will remove it's block from those completed.
    This will therefore force the respondent to revisit that block.
    The dependent answers themselves remain untouched.
    :param answer_id: the answer that has changed
    :param questionnaire_store: holds the completed blocks
    :return: None
    """
    answer_in_repeating_group = schema.answer_is_in_repeating_group(answer_id)
    dependencies = schema.dependencies[answer_id]

    for dependency in dependencies:
        dependency_in_repeating_group = schema.answer_is_in_repeating_group(dependency)

        answer = schema.get_answer(dependency)
        question = schema.get_question(answer['parent_id'])
        block = schema.get_block(question['parent_id'])

        if dependency_in_repeating_group and not answer_in_repeating_group:
            questionnaire_store.remove_completed_blocks(group_id=block['parent_id'], block_id=block['id'])
        else:
            location = Location(block['parent_id'], group_instance, block['id'])
            if location in questionnaire_store.completed_blocks:
                questionnaire_store.remove_completed_blocks(location=location)

def _remove_answer_from_questionnaire_store(answer_id, questionnaire_store,
                                            group_instance=0):
    questionnaire_store.answer_store.remove(answer_ids=[answer_id],
                                            group_instance=group_instance,
                                            answer_instance=0)

@save_questionnaire_store
def update_questionnaire_store_with_answer_data(questionnaire_store, location, answers, schema):

    survey_answer_ids = schema.get_answer_ids_for_block(location.block_id)

    for answer in [a for a in answers if a.answer_id in survey_answer_ids]:
        questionnaire_store.answer_store.add_or_update(answer)

    if location not in questionnaire_store.completed_blocks:
        questionnaire_store.completed_blocks.append(location)

def _check_same_survey(url_eq_id, url_form_type, url_collection_id, session_eq_id, session_form_type, session_collection_id):
    if url_eq_id != session_eq_id \
        or url_form_type != session_form_type \
            or url_collection_id != session_collection_id:
        raise MultipleSurveyError

def _evaluate_skip_conditions(block_json, location, schema, answer_store, metadata):
    for question in schema.get_questions_for_block(block_json):
        if 'skip_conditions' in question:
            skip_question = evaluate_skip_conditions(question['skip_conditions'], schema, metadata, answer_store, location.group_instance)
            question['skipped'] = skip_question
            for answer in question['answers']:
                if answer['mandatory'] and skip_question:
                    answer['mandatory'] = False

    return block_json

def extract_answer_id_and_instance(answer_instance_id):
    matches = re.match(r'^household-(\d+)-(first-name|middle-names|last-name)$', answer_instance_id)

    if matches:
        index, answer_id = matches.groups()
    else:
        answer_id = answer_instance_id
        index = 0

    return answer_id, int(index)

def _redirect_to_location(collection_id, eq_id, form_type, location):
    return redirect(url_for('questionnaire.get_block', eq_id=eq_id, form_type=form_type, collection_id=collection_id,
                            group_id=location.group_id,
                            group_instance=location.group_instance, block_id=location.block_id))

def _get_context(full_routing_path, block, current_location, schema, form=None):
    metadata = get_metadata(current_user)
    answer_store = get_answer_store(current_user)
    schema_context = _get_schema_context(full_routing_path, current_location.group_instance, metadata, answer_store, schema)
    rendered_block = renderer.render(block, **schema_context)

    return build_view_context(block['type'], metadata, schema, answer_store, schema_context, rendered_block, current_location, form=form)

def _get_block_json(current_location, schema, answer_store, metadata):
    block_json = schema.get_block(current_location.block_id)
    return _evaluate_skip_conditions(block_json, current_location, schema, answer_store, metadata)

def _get_schema_context(full_routing_path, group_instance, metadata, answer_store, schema):
    answer_ids_on_path = get_answer_ids_on_routing_path(schema, full_routing_path)

    return build_schema_context(metadata=metadata,
                                schema=schema,
                                answer_store=answer_store,
                                group_instance=group_instance,
                                answer_ids_on_path=answer_ids_on_path)

def _get_front_end_navigation(answer_store, current_location, metadata, schema, routing_path=None):
    completed_blocks = get_completed_blocks(current_user)
    navigation = Navigation(schema, answer_store, metadata, completed_blocks,
                            routing_path, get_completeness(current_user))
    block_json = schema.get_block(current_location.block_id)
    if block_json['type'] != 'Introduction':
        return navigation.build_navigation(current_location.group_id, current_location.group_instance)

    return None

def get_page_title_for_location(schema, current_location, metadata, answer_store):
    block = schema.get_block(current_location.block_id)
    if block['type'] == 'Interstitial':
        group = schema.get_group(current_location.group_id)
        page_title = '{group_title} - {survey_title}'.format(group_title=group['title'], survey_title=schema.json['title'])
    elif block['type'] == 'Question':
        first_question = next(schema.get_questions_for_block(block))
        question_title = get_question_title(first_question, answer_store, schema, metadata, current_location.group_instance)
        page_title = '{question_title} - {survey_title}'.format(question_title=question_title, survey_title=schema.json['title'])
    else:
        page_title = schema.json['title']

    return TemplateRenderer.safe_content(page_title)

def _build_template(current_location, context, template, schema, answer_store, metadata, routing_path=None):
    front_end_navigation = _get_front_end_navigation(answer_store, current_location, metadata, schema, routing_path)
    previous_location = path_finder.get_previous_location(current_location)
    previous_url = previous_location.url(metadata) if previous_location is not None else None

    return _render_template(context, current_location, template, front_end_navigation, previous_url, schema, metadata, answer_store)

@with_session_timeout
@with_questionnaire_url_prefix
@with_metadata_context
@with_analytics
@with_legal_basis
def _render_template(context, current_location, template, front_end_navigation, previous_url, schema, metadata, answer_store, **kwargs):
    page_title = get_page_title_for_location(schema, current_location, metadata, answer_store)

    return render_template(
        template,
        content=context,
        current_location=current_location,
        navigation=front_end_navigation,
        previous_location=previous_url,
        page_title=page_title,
        metadata=kwargs.pop('metadata_context'),  # `metadata_context` is used as `metadata` in the jinja templates
        **kwargs,
    )

def request_wants_json():
    best = request.accept_mimetypes \
        .best_match(['application/json', 'text/html'])
    return best == 'application/json' and \
        request.accept_mimetypes[best] > \
        request.accept_mimetypes['text/html']


#! /usr/bin/env python
import sys
import csv
import screed
import random
import argparse

import sourmash

import sequtils                 # local import

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('genome')
    parser.add_argument('-e', '--error-rate', type=float, default=.01)
    parser.add_argument('-r', '--read-length', type=int, default=100,
                        help="Length of reads to generate")
    parser.add_argument("-S", "--seed", dest="seed", help="Random seed", type=int,
                        default=1)
    parser.add_argument("-k", "--ksize", default=31, help="k-mer size")
    parser.add_argument("-o", "--output", required=True,
                        help="CSV output of detection curve")

    args = parser.parse_args()

    READLEN=args.read_length
    ERROR_RATE=args.error_rate
    NUM_FRACMINHASH = 5

    random.seed(args.seed)                  # make this reproducible, please.

    records = list(screed.open(args.genome))
    assert len(records) == 1
    record = records[0]

    genome = record.sequence
    len_genome = len(genome)

    total_mh = sourmash.MinHash(0, args.ksize, scaled=1)
    total_mh.add_sequence(genome)
    all_hashes = set(total_mh.hashes)

    # make NUM_FRACMINHASH minhashes each with different mmh seeds
    all_hashes_list = []
    scaled_mh_list = []
    for i in range(NUM_FRACMINHASH):
        smh = sourmash.MinHash(0, args.ksize, scaled=1000, seed=i + 42)
        all_hashes_i = smh.copy_and_clear()
        all_hashes_i.add_sequence(genome)
        scaled_mh_list.append(smh)
        all_hashes_list.append(all_hashes_i)

    print('genome size:', len_genome, file=sys.stderr)
    print('readlen:', READLEN, file=sys.stderr)
    print('error rate:', ERROR_RATE, file=sys.stderr)
    print('num k-mers:', len(total_mh))

    reads_mut = 0
    total_mut = 0

    print(f"Read in template genome {0} of length {1} from {2}".format(record["name"], len_genome, args.genome), file=sys.stderr)
    print(f"Generating reads of length {READLEN} with an error rate of 1 in {ERROR_RATE}", file=sys.stderr)

    it = sequtils.generate_mutated_reads(genome, READLEN, ERROR_RATE)
    it = iter(it)

    fp = open(args.output, 'w', newline="")
    csv_w = csv.writer(fp)
    headers = ['num_reads', 'coverage', 'n_detected', 'f_detected']
    for i in range(NUM_FRACMINHASH):
        headers.append(f"smash_count_{i}")
    csv_w.writerow(headers)
    csv_w.writerow([0, 0, 0, 0] + [0]*NUM_FRACMINHASH)

    n_reads = 0
    total_bp_in_reads = 0
    f01 = len(all_hashes) * 0.1

    remaining_hashes = set(all_hashes)
    while len(remaining_hashes) > f01:
        start, read, read_mutations = next(it)

        if read_mutations:
            reads_mut += 1
            total_mut += read_mutations

        n_reads += 1
        total_bp_in_reads += len(read)

        # first, track _all_ hashes for actual k-mer detection
        mh = total_mh.copy_and_clear()
        mh.add_sequence(read)
        remaining_hashes -= set(mh.hashes)

        n_detected = len(all_hashes) - len(remaining_hashes)
        f_detected = n_detected / len(all_hashes)
        coverage = total_bp_in_reads / len_genome

        # now, track sourmash detection & intersect with legit hashes:
        smash_detection = []
        for smh, all_hashes_i in zip(scaled_mh_list, all_hashes_list):
            smh.add_sequence(read)
            smh_hashes = set(smh.hashes)
            smh_hashes.intersection_update(all_hashes_i.hashes)
            smash_detection.append(len(smh_hashes))

        csv_w.writerow([n_reads, f"{coverage:.4f}", n_detected, f"{f_detected:.4f}"] + smash_detection)

        sys.stdout.write(u'\r\033[K')
        sys.stdout.write(f"...{n_reads} reads, {len(all_hashes)} missing k-mers, {total_bp_in_reads / len_genome:.2f} coverage")
        sys.stdout.flush()

    fp.close()

if __name__ == '__main__':
    sys.exit(main())


import math
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

#Dane początkowe
k1 = 1
m = 1
h = 0.05

x0 = 10
vx0 = 0

w1 = math.sqrt(k1/m)
A1 = math.sqrt((vx0*vx0)/(w1*w1) + (x0*x0))

iloscPunktow = 1000

#oś XY
setXl = 0
setXr = 55
setYl = 49.95
setYr = 50.04

if(vx0 <= 0):
   fi1 = math.acos(x0/A1) * 180/math.pi
else:
   fi1 = -math.acos(x0/A1) * 180/math.pi

#Wypisanie danych poczatkowych
print("\nk1 = {0}\nm = {1}\nh = {2}\nx0 = {3}\nvx0 = {4}\nw1 = {5}\nA1 = {6}\nfi1 = {7}"
      .format(k1, m, h, x0, vx0, w1, A1, fi1))
print("\nIlosć punktów = {0}".format(iloscPunktow))

#Czas
time = []
for i in range(0, iloscPunktow+1):
    time.append(round((i*h), 2))
    #print(time[i])

#rozwiazanie dokladne listy oraz wartosci poczatkowe
dokladneX = []
dokladneVX = []
dokladneX.append(x0)
dokladneVX.append(vx0)
dokladneE = []

#metoda eulera listy oraz wartosci poczatkowe
eulerX = []
eulerVX = []
eulerX.append(x0)
eulerVX.append(vx0)
eulerE = []

#metoda punktu posredniego listy oraz wartosci poczatkowe
posredniaX = []
posredniaVX = []
posredniaX.append(x0)
posredniaVX.append(vx0)
posredniaE = []

#metoda verleta listy oraz wartosci poczatkowe
verletX = []
verletVX = []
verletX.append(x0)
verletVX.append(vx0)
verletE = []

#metoda beemana listy oraz wartosci poczatkowe
beemanX = []
beemanVX = []
beemanX.append(x0)
beemanVX.append(vx0)
beemanE = []

#uzupelnianie list
for i in range(1, iloscPunktow+1):
    #dokladna
    dokX = A1 * math.cos(w1 * time[i] + fi1 * math.pi / 180)
    dokVX = -A1 * w1 * math.sin(w1 * time[i] + fi1 * math.pi/180)
    dokladneX.append(dokX)
    dokladneVX.append(dokVX)
    #euler
    eulX = eulerX[i - 1] + eulerVX[i - 1] * h
    eulVX = eulerVX[i - 1] - (w1 * w1) * eulerX[i - 1] * h
    eulerX.append(eulX)
    eulerVX.append(eulVX)
    #posrednia
    posX = posredniaX[i-1] + posredniaVX[i-1] * h - 0.5 * (w1 * w1) * posredniaX[i-1] * (h * h)
    posVX = posredniaVX[i-1] - (w1 * w1) * posredniaX[i-1] * h
    posredniaX.append(posX)
    posredniaVX.append(posVX)
    #verlet
    verX = verletX[i - 1] + verletVX[i - 1] * h - 0.5 * (w1 * w1) * verletX[i - 1] * (h * h)
    verletX.append(verX)
    verVX = verletVX[i - 1] - 0.5 * (w1 * w1) * (verletX[i - 1] + verletX[i]) * h
    verletVX.append(verVX)
    #beeman
    # z verleta liczone
    if(i == 1):
        beemanX.append(verletX[1])
        beemanVX.append(verletVX[1])
    else:
        bemX = beemanX[i - 1] + beemanVX[i - 1] * h + (w1 * w1) * (beemanX[i - 2] - 4 * beemanX[i - 1]) * (h * h)/6
        beemanX.append(bemX)
        bemVX = beemanVX[i - 1] + (w1 * w1) * (beemanX[i - 2] - 5 * beemanX[i - 1] - 2 * beemanX[i]) * h/6
        beemanVX.append(bemVX)

#energia

for i in range(0, iloscPunktow+1):
    dokE = 0.5 * k1 * (A1*A1)
    dokladneE.append(dokE)
    eulE = m * (eulerVX[i] * eulerVX[i])/2 + k1 * (eulerX[i] * eulerX[i]/2)
    eulerE.append(eulE)
    posE = m * (posredniaVX[i] * posredniaVX[i])/2 + k1 * (posredniaX[i] * posredniaX[i]/2)
    posredniaE.append(posE)
    verE = m * (verletVX[i] * verletVX[i])/2 + k1 * (verletX[i] * verletX[i]/2)
    verletE.append(verE)
    bemE = m * (beemanVX[i] * beemanVX[i])/2 + k1 * (beemanX[i] * beemanX[i]/2)
    beemanE.append(bemE)

#Animacja
xdata = []
ydata = []

xdata2 = []
ydata2 = []

xdata3 = []
ydata3 = []

font1 = {'family': 'serif', 'color': 'blue', 'size': 20}
font2 = {'family': 'serif', 'color': 'darkred', 'size': 15}
fig, ax = plt.subplots()
ax.set_xlim(setXl, setXr)
ax.set_ylim(setYl, setYr)
plt.title("Energia całkowita oscylatora", fontdict=font1)
plt.xlabel("t", fontdict = font2)
plt.ylabel("E", fontdict = font2)

line, = ax.plot(0, 0, '.') #niebieski
line2, = ax.plot(0, 0, 'r.') #czerwony
line3, = ax.plot(0, 0, 'g.') #zielony

line.set_label('rozwiązanie Dokładne')
line2.set_label('metoda Verleta')
line3.set_label('metoda Beemana')
ax.legend()

def animation_frame(i):
    xdata.append(time[i])
    ydata.append(dokladneE[i])

    xdata2.append(time[i])
    ydata2.append(verletE[i])

    xdata3.append(time[i])
    ydata3.append(beemanE[i])

    line.set_xdata(xdata)
    line.set_ydata(ydata)

    line2.set_xdata(xdata2)
    line2.set_ydata(ydata2)

    line3.set_xdata(xdata3)
    line3.set_ydata(ydata3)

    return line, line2, line3,

animation = FuncAnimation(fig, func = animation_frame, frames = np.arange(0, iloscPunktow + 1, 1), interval = 5)
plt.show()


import os
import math
import numpy as np
from tqdm import tqdm
import pickle
import torch
import torch.nn as nn
from torch.autograd import Variable
from torch.nn import functional as F
from models import l2norm

## Memory
class Memory(nn.Module):
    def __init__(self, mem_size=500000, feat_dim=256, margin=1, topk=1000, update_rate=0.1):
        super(Memory, self).__init__()
        self.mem_size = mem_size
        self.feat_dim = feat_dim
        self.Mem = nn.Parameter(torch.zeros(mem_size, feat_dim))
        self.Ages = nn.Parameter(torch.zeros(mem_size, 1))
        self.topk = topk
        self.margin = margin
        self.update_rate = update_rate
        # At this time, we don't train mem by gradient descent
        self.Mem.requires_grad = False
        self.Ages.requires_grad = False

    def update_mem(self, x, labels):
        with torch.no_grad():
            self.Mem[labels] = l2norm(self.update_rate * x.data + (1 - self.update_rate) * self.Mem[labels])

    def update_mem_with_ages(self, x, labels):
        with torch.no_grad():
            self.Ages[labels] += 1.
            self.Mem[labels] = l2norm(x.data + self.Mem[labels] * self.Ages[labels])

    def search_l2(self, x, topk):
        batch_size = x.size(0)
        distmat = torch.pow(x, 2).sum(dim=1, keepdim=True).expand(batch_size, self.mem_size) + \
                  torch.pow(self.Mem, 2).sum(dim=1, keepdim=True).expand(self.mem_size, batch_size).t()
        distmat.addmm_(x, self.Mem.t(), beta=1, alpha=-2)
        distances, indices = torch.topk(distmat, topk, largest=False)
        return distances, indices

    def compute_l2loss(self, x, labels):
        """ L2 Distance
        Args:
            x: feature matrix with shape (batch_size, feat_dim).
            labels: ground truth labels with shape (batch_size).
        """
        batch_size = x.size(0)
        distmat = torch.pow(x, 2).sum(dim=1, keepdim=True).expand(batch_size, self.mem_size) + \
                  torch.pow(self.Mem, 2).sum(dim=1, keepdim=True).expand(self.mem_size, batch_size).t()
        distmat.addmm_(x, self.Mem.t(), beta=1, alpha=-2)
        classes = torch.arange(self.mem_size).long()
        if labels.is_cuda:
            classes = classes.cuda()
        labels = labels.unsqueeze(1).expand(batch_size, self.mem_size)
        mask = labels.eq(classes.expand(batch_size, self.mem_size))

        dist1 = distmat * mask.float()
        min_loss = dist1.clamp(min=1e-12, max=1e+12).sum(1)

        dist2 = distmat * (1.0 - mask.float())
        max_loss = torch.topk(dist2, self.topk, dim=1, largest=False)[0].sum(1) /  (self.topk - 1)
        loss = F.relu(min_loss - max_loss + self.margin)
        return loss.mean(), min_loss.mean(), max_loss.mean()


# -*- coding: utf-8 -*-
from __future__ import division
import scrapy
from scrapy import Request
# from street_food.items import StreetFoodItem, StreetFoodDatTimeItem
from street_food.items import StreetFoodDatTimeItem
from street_food.spiders import tools
import json
from urllib import urlopen
# import random
from street_food.tools import basic_tools

class GetFoodOffTheGrid(scrapy.Spider):
    name = "offthegrid"
    allowed_domains = ["offthegridmarkets.com", "offthegrid.com"]

    start_urls = [
        'https://offthegrid.com/otg-api/passthrough/markets.json/?latitude=37.7749295&longitude=-122.41941550000001&sort-order=distance-asc'
    ]

    custom_settings = {
        "ITEM_PIPELINES": {
            "street_food.pipelines.ApiUploader": 10,
        }
    }

    def parse(self, response):
        ''' Parse list of markets '''

        markets = json.loads(response.text)

        market_url = "https://offthegrid.com/otg-api/passthrough/markets/{}.json/"

        # Get list of markets in San Francisco.
        for market in [market for market in markets["Markets"]]:
            market = market['Market']

            market_id = market['id']

            yield Request(market_url.format(market_id),
                          callback=self.parse_market)

    def parse_market(self, response):
        ''' Parse a market '''

        # load Maize Vendors.
        maizeresp = urlopen('http://yumbli.herokuapp.com/api/v1/allkitchens/?format=json')
        vendors = json.loads(maizeresp.read().decode('utf8'))
        maizevendors = {}
        for v in vendors:
            maizevendors[v['name'].lower()] = v['id']

        item = StreetFoodDatTimeItem()

        market = json.loads(response.text)
        market_detail = market["MarketDetail"]["Market"]["Market"]
        market_events = market["MarketDetail"]["Events"]

        # Market Address.
        market_address = market_detail["address"].strip()
        market_city = market_detail["city"].strip()
        full_address = "{} {}".format(market_address, market_city)

        # Market location.
        market_latitude = market_detail['latitude']
        market_longitude = market_detail['longitude']
        # geolocation = "{} {}".format(market_latitude, market_longitude)

        # Add data to item.

        item['address'] = full_address

        # Parse market events.
        for event in market_events:

            start_datetime, end_datetime = tools.get_start_end_datetime(event['Event'])

            item['start_datetime'] = start_datetime
            item['end_datetime'] = end_datetime

            # Parse vendors of event.
            for vendor in event['Vendors']:
                vendor_name = vendor['name']
                item['VendorName'] = vendor_name
                # randlongpos = random.randint(-150, 150) / 1000000
                # randlatpos = random.randint(-200, 200) / 1000000

                # item['latitude'] = abs(float(market_latitude)) + randlatpos
                # abs then *-1 b/c off the grid has some wrong values
                # item['longitude'] = abs(float(market_longitude))*-1 + randlongpos

                item['latitude'] = basic_tools.mix_location(market_latitude)
                item['longitude'] = basic_tools.mix_location(market_longitude)

                if vendor_name and vendor_name.lower() in maizevendors.keys():
                    item['maize_status'] = 'found'
                    item['maize_id'] = maizevendors[vendor_name.lower()]
                else:
                    item['maize_status'] = 'not found'
                    item['maize_id'] = 'n/a'

                yield item


'''
boss class
'''

import pygame

class Boss(pygame.sprite.Sprite):

    def __init__(self,laser):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("images/Boss.gif").convert()
        self.rect = self.image.get_rect()
        self.rect.x = 500
        self.rect.y = 0
        self.health = 200
        self.laser = laser
        self.lasertimer = 0
        self.left = False
        self.right = True

    #update the boss
    def update(self):
        self.movement()
        self.attack()

    #get the health
    def getHealth(self):
        return self.health

    #set the health
    def setHealth(self):
        self.health = self.health - 10

    #laser attack of the boss
    def attack(self):

        self.lasertimer += 1

        if self.lasertimer == 20:
            self.laser.rect.x = self.rect.x + 50
            self.laser.rect.y = self.rect.y

        if self.lasertimer > 20:
            self.laser.rect.y += 15
            if self.laser.rect.y > 600:
                self.lasertimer = 0
                self.laser.rect.x = -500
                self.laser.rect.y = -500

    #set up movement for boss
    def movement(self):
        if self.rect.x > 900:
            self.right = False
            self.left = True

        if self.rect.x < 50:
            self.left = False
            self.right = True

        if self.left:
            self.rect.x -= 10
        if self.right:
            self.rect.x += 10


import datetime
import random
import yaml

from requests import get

def compute_median(lst):
    """
    Вычисление медианты списка
    :param lst: входящий список значений
    :return: медиана
    """
    quotient, remainder = divmod(len(lst), 2)
    return lst[quotient] if remainder else sum(sorted(lst)[quotient - 1:quotient + 1]) / 2

def compute_avg(lst):
    """
    Вычисление среднего арифметические значения списка
    :param lst: входящий список значений
    :return: среднее арифметические значение
    """
    return sum(lst) / len(lst)

def usage_type(avg, median):
    """
    Вычисление типа использования
    :param avg: среднее занечение метрик
    :param median: медианное значение метрик
    :return: возврат значения типа использования
    """
    if (avg < 1.25 * median) and (avg > 0.75 * median):
        return "стабильна"
    elif avg > 1.25 * median:
        return "скачки"
    else:
        return "снижения"

def intensity(median):
    """
    Вычисление интенсивности использования
    :param median: медианное значение метрик
    :return: возврат значения интенсивности
    """
    if (0 < median) and (median <= 30):
        return "низкая"
    if (30 < median) and (median <= 60):
        return "умеренная"
    if (60 < median) and (median <= 90):
        return "высокая"
    return "запредельная"

def decision(usage, intens):
    """
    Принятие решения о дальнецшем использовании ресурса
    :param usage: тип использования
    :param intens: интенсивности использованя
    :return: возврат решения
    """
    if intens == "низкая":
        return "отказаться"
    if intens == "запредельная":
        return "усилить"
    if intens == "умеренная" and usage in ("стабильна", "скачки"):
        return "отсавить"
    if intens == "высокая" and usage in ("снижения", "стабильна"):
        return "отсавить"
    if usage == "снижения" and intens == "умеренная":
        return "отказаться"
    if usage == "скачки" and intens == "высокая":
        return "усилить"

def obj_creator(data):
    """
    Генератор обьекта заданной структуры из сырых данных
    :param data: сырые данные
    :return: Обект заданной тсруктуры
    """
    final_data = {}
    for msg in data:
        team_name, project, resource, due, resource_metric = msg
        a = {"time": due, "value": int(resource_metric)}
        final_data.setdefault(team_name, {}).setdefault(project, {}).setdefault(resource, []).append(a)
    return final_data

def get_data_from_http(url):
    """
    Генерация списка метрик по HTTP
    :param url: адресс веб сервера источника метрик
    :return: лист метрик
    """
    rnd_seed = random.randint(1, 3)
    team_raw = get(url + f"/monitoring/infrastructure/using/summary/{rnd_seed}").text.split("$")
    final_list = []
    for team_raw_data in team_raw:
        team_name, team_data = team_raw_data.split("|")
        team_data = team_data.split(";")
        for team_data_split_data in team_data:
            project, resource, due, resource_metric = team_data_split_data[1:-1].split(",")
            yr, mt, dy = due[0:10].split("-")
            date = datetime.date(year=int(yr), month=int(mt), day=int(dy))
            final_list.append((team_name, project, resource, date, int(resource_metric)))
    return final_list

if __name__ == '__main__':
    print("start")

    full_msg = get_data_from_http("http://127.0.0.1:21122/")
    final_data = obj_creator(full_msg)

    yaml_price = get("http://127.0.0.1:21122/monitoring/infrastructure/using/prices").text
    price_full = yaml.safe_load(yaml_price)["values"]

    print("Ресурс|Значение|среднее|медиана|использование|интенсивность|решение|дата последний метрики|цена")
    for name, prj in final_data.items():
        print(f"команда {name}")
        for prj_name, res_values in prj.items():
            summ = 0
            for res, values in res_values.items():
                value_list = []
                time = []
                for value in values:
                    value_list.append(value["value"])
                    time.append(value["time"])
                last_time = time[-1] + datetime.timedelta(14)
                median = compute_median(value_list)
                avg = compute_avg(value_list)
                usage = usage_type(avg, median)
                intens = intensity(median)
                final_decision = decision(usage, intens)
                cost = price_full[prj_name]
                summ += int(cost[res])
                print(f"{prj_name} | {res} | {avg} | {median} | {usage} | {intens} | {final_decision} | {last_time} | {cost[res]}")
            print(f"Цена за ресурс = {summ}")


#!/usr/bin/env python3
#encoding: UTF-8

# To change this license header, choose License Headers in Project Properties.
# To change this template file, choose Tools | Templates
# and open the template in the editor.
import numpy as np
import matplotlib.pyplot as plt
import math
import TrashCan.Mathieson as mat

import C.PyCWrapper as PCWrap
import Util.plot as uPlt
import Util.dataTools as tUtil

def vErf(x):
    y = np.zeros( x.shape )
    for i in range( x.shape[0]):
        y[i] = math.erf( x[i] )
    return y

def computeGaussian1D( x,  mu=0.0, var=1.0):
    # print ( "???", __name__, x[-1], x.shape )
    # print "x", x
    TwoPi = 2 * np.pi
    SqrtTwoPi = np.sqrt( TwoPi )
    sig = np.sqrt(var)
    u = (x - mu) / sig
    # print "u", u
    u = - 0.5 * u * u
    cst = 1.0 / ( sig * SqrtTwoPi)
    y = cst * np.exp( u )
    return y

def gaussianIntegral(x):
    mu0 = 0.0
    var0 = 1.0
    sig0 = np.sqrt( var0 )
    cstx = 1.0 / ( np.sqrt(2.0)*sig0 )
    integral = vErf( (x - mu0) * cstx )
    return integral

class TabulatedChargeIntegration:

  # Spline implementation of the book "Numerical Analysis" - 9th edition
  # Richard L Burden, J Douglas Faires
  # Section 3.5, p. 146
  # Restrictions : planed with a regular sampling (dx = cst)
  # spline(x) :[-inf, +inf] -> [-1/2, +1/2]
  # Error < 7.0 e-11 for 1001 sampling between [0, 3.0]
  def __init__(self, x, f, dx, lDerivate, rDerivate ):
    self.nTabulations = x.size
    N = x.size
    self.a = np.copy( f )
    self.b = np.zeros(N)
    self.c = np.zeros(N)
    self.d = np.zeros(N)
    self.dx = dx

    # Step 1
    # for (i = 0; i < n - 1; ++i) h[i] = x[i + 1] - x[i];
    #for i in range(0, N-1):
    #  self.h[i] = x[i+1] - x[i];
    # h = x[0:N-1] = x[1:N] - x[0:N-1]
    h = self.dx

    # Step 2
    # for (i = 1; i < n-1; ++i)
    #    A[i] = 3 * (a[i + 1] - a[i]) / h[i] - 3 * (a[i] - a[i - 1]) / h[i - 1];
    # A[1:N-1] = 3 * (a[2:N] - a[1:N-1]) / h[1:N-1]  -  3 * (a[1:N-1] - a[0:N-2]) / h[0:N-2]];

    # Step 2 & 3
    alpha = np.zeros(N)
    # alpha[0] = 3.0 / self.h[0] * (f[1] - f[0]) - 3*lDerivate
    alpha[0] = 3.0 / h * (f[1] - f[0]) - 3*lDerivate
    # alpha[N-1] =  3*rDerivate - 3.0 / self.h[N-2] * (f[N-1] - f[N-2])
    alpha[N-1] =  3*rDerivate - 3.0 / h * (f[N-1] - f[N-2])
    # for (i = 1; i < n-1; ++i)
    for i in range(1, N-1):
      # alpha[i] = 3.0/self.h[i] * (f[i+1] - f[i]) - 3.0/self.h[i-1] * (f[i] - f[i-1]);
      alpha[i] = 3.0/h * (f[i+1] - f[i]) - 3.0/h * (f[i] - f[i-1]);

    # Step 4 to 6 solve a tridiagonal linear system

    # Step 4
    l = np.zeros(N)
    mu = np.zeros(N)
    z = np.zeros(N)
    # l[0] = 2 * self.h[0]
    l[0] = 2 * h
    mu[0] = 0.5
    z[0] = alpha[0] / l[0]

    # Step 5
    # for (i = 1; i < n - 1; ++i) {
    for i in range(1, N-1):
      # l[i] = 2 * (x[i+1] - x[i-1]) - self.h[i-1] * mu[i - 1];
      # mu[i] = self.h[i] / l[i];
      # z[i] = (alpha[i] - self.h[i-1]*z[i-1]) / l[i];
      l[i] = 2 * (x[i+1] - x[i-1]) - h * mu[i-1];
      mu[i] = h / l[i];
      z[i] = (alpha[i] - h*z[i-1]) / l[i];

    # Step 6 & 7
    # l[N-1] = self.h[N-2]*(2.0-mu[N-2])
    # z[N-1] = (alpha[N-1] - self.h[N-2]*z[N-2]) / l[N-1]
    l[N-1] = h*(2.0-mu[N-2])
    z[N-1] = (alpha[N-1] - h*z[N-2]) / l[N-1]

    self.c[N-1] = z[N-1]
    # for (j = n - 2; j >= 0; --j) {
    for j in range(N-2, -1, -1):
      self.c[j] = z[j] - mu[j] * self.c[j+1]
      # self.b[j] = (f[j+1]-f[j]) / self.h[j] - self.h[j]/3.0 * (self.c[j+1] + 2*self.c[j])
      # self.d[j] = (self.c[j+1]-self.c[j]) / (3 * self.h[j])
      self.b[j] = (f[j+1]-f[j]) / h - h/3.0 * (self.c[j+1] + 2*self.c[j])
      self.d[j] = (self.c[j+1]-self.c[j]) / (3 * h)

  def splineAtanTanh( self, x ):
      a = self.a
      b = self.b
      c = self.c
      d = self.d
      N = self.nTabulations

      signX = np.where( x >= 0, 1.0, -1.0 )
      # unsigned x
      uX = x * signX
      # 0.49999999724624
      # 0.499999996965014 point precedent f0(2OO-1)
      # 0.49999999724624 f0(200)
      # 0.499999997245073 f(200-1)
      # 0.499999997232819 y[200-1]
      # 0.49999999748923 y[200]
      # 0.       890
      # 0.49999999724624 f0(200)
      np.set_printoptions(precision=15)
      # print("???  x / self.dx", x / self.dx)
      cst = 1.0 / self.dx
      u = np.trunc( uX * cst + self.dx*0.1)
      # idx = u.astype(np.int)
      idx = np.int32(u)
      # print("??? idx ", idx)
      idx = np.where( idx >= N, N-1, idx)
      h = np.where( idx < N-1, uX - idx * self.dx, 0)
      # h = x - idx * self.dx
      # print("??? idx filter large indexes", idx)

      print ("uX ",  uX)
      print ("h ",  h)
      print ("f(x0) ",  a[idx])
      print ("df|dx0",  h*( b[idx] + h*( c[idx] + h *(d[idx]))))
      print ("f, ",  a[idx] + h*( b[idx] + h*( c[idx] + h *(d[idx]))))
      f = signX * (a[idx] + h*( b[idx] + h*( c[idx] + h *(d[idx]))))
      return f

if __name__ == "__main__":

    #pcWrap = PCWrap.setupPyCWrapper()
    #pcWrap.initMathieson()

    xPrecision = 1.0e-3
    xLimit = 3.0
    N = int(xLimit / xPrecision) + 1
    x = np.linspace(0.0, xLimit, N)
    dxVar = x[1:] - x[0:-1]
    print("Verify sampling N, xPrecision, dxMin, dxMax", N, xPrecision, np.min(dxVar), np.max(dxVar))
    dx = xPrecision
    mat0 = mat.Mathieson( 0, 1.0 )
    leftDerivate = 2.0 * mat0.curK4x * mat0.curSqrtK3x * mat0.curK2x * mat0.curInvPitch
    print("leftDerivate", leftDerivate)
    # leftDerivate = 2.77
    y = mat0.computeAtanTanh( x)
    tf = TabulatedChargeIntegration(x, y, dx, leftDerivate, 0.0)

    """
    m = int( N/2 )
    print("N", N, x.size )
    print("x ", x[0], x[1], x[2], '...', x[m-1], x[m], x[m+1], "...", x[-3], x[-2], x[-1] )
    print("\n")
    print("maxErr", np.max(np.abs(f-y)) )
    """

    fig, ax = plt.subplots(nrows=2, ncols=2, figsize=(10, 7))
    # Spline at sampling points
    f = tf.splineAtanTanh(x)
    ax[0,0].plot( x, y)
    ax[0,0].scatter( x, f, marker='x', color="red")
    # , markersize=4)
    ax[0,0].set_ylabel( "atan(tanh(x0)) and spline(x0) [in red]")
    #
    ax[0,1].scatter( x, f-y, marker='x')
    ax[0,1].set_ylabel( "atan(tanh(x0)) - spline(x0)")

    # Far away points
    print("--------------------")
    x1 = x + 0.0095
    y1 = mat0.computeAtanTanh( x1)
    f1 = tf.splineAtanTanh(x1)
    print("y1", y1)
    ax[1,0].scatter( x1, f1-y1, marker='x')
    ax[1,0].set_ylabel( "atan(tanh(x1)) - spline(x1)")
    print("--------------------")
    # RND
    xrnd = (np.random.ranf(20*N) * 2  - 1.0) * (xLimit + 1.0)
    frnd = tf.splineAtanTanh(xrnd)
    yrnd = mat0.computeAtanTanh(xrnd)
    #
    ax[1,1].scatter( xrnd, frnd-yrnd, marker='x')
    ax[1,1].set_ylabel( "atan(tanh(rnd)) - spline(rnd)")
    # relative error
    # ax[1,1].scatter( x1[1:], (f1[1:]-y1[1:]) / y1[1:] )
    #
    print("maxErr f1", np.max(np.abs(f1-y1)) )
    print( "convergence last point y, dy ",  y1[-1], np.max(np.abs(f1[-1]-y1[-1])))
    np.set_printoptions(precision=15)
    print( "f(x) x=[0, ..,9]", mat0.computeAtanTanh( np.arange(10.0)) - 0.5 )

    print("FIRST POINT")
    tf.splineAtanTanh( np.array([0.0]) )
    print("Function",  mat0.computeAtanTanh( np.array([0.0])) )
    print("Last POINT")
    tf.splineAtanTanh( np.array([2.0]) )
    print("Function",  mat0.computeAtanTanh( np.array([2.0])) )
    print("Outer POINT")
    tf.splineAtanTanh( np.array([15.0]) )
    print("Function",  mat0.computeAtanTanh( np.array([15.0])) )

    xx = np.arange(6.0)
    print("xx",  xx )
    print("f(xx) - 0.5",  mat0.computeAtanTanh( xx ) - 0.5)

    plt.show()


import numpy as np
import matplotlib.pyplot as plt
from scipy import signal

def load_data(filename):
    # 读入数据文件
    data = np.loadtxt(filename)
    return data

def plot_signal_waveform(data, fs):
    # 绘制信号波形
    duration = len(data) / fs # 持续时间，单位为秒
    time = np.linspace(0, duration, len(data))
    plt.subplot(3,1,1)
    plt.plot(time, data)
    plt.xlabel("Time (s)")
    plt.ylabel("Amplitude")
    plt.title("Original Signal")

def plot_stft_spectrogram(data, fs, window, nperseg, noverlap):
    # 进行STFT
    f, t, Zxx = signal.stft(data, fs=fs, window=window, nperseg=nperseg, noverlap=noverlap)

    # 绘制时频图
    plt.subplot(3,1,2)
    plt.pcolormesh(t, f, np.abs(Zxx), cmap='YlOrBr')
    plt.title('STFT Magnitude')
    plt.ylabel('Frequency [Hz]')
    plt.xlabel('Time [sec]')

def plot_fft_magnitude(data, fs):
    # 进行FFT
    fft_data = np.fft.fft(data)
    freqs = np.fft.fftfreq(len(fft_data), 1/fs)

    # 绘制FFT图
    plt.subplot(3,1,3)
    plt.plot(freqs, np.abs(fft_data))
    plt.title('FFT Magnitude')
    plt.ylabel('Magnitude')
    plt.xlabel('Frequency [Hz]')

if __name__ == '__main__':
    filename = 'Software/data/1.csv'
    data = load_data(filename)
    fs = 1000
    window = signal.windows.hann(128) # 窗函数
    nperseg = 128 # STFT段长
    noverlap = nperseg//2 # STFT重叠长度

    plot_signal_waveform(data, fs)
    plot_stft_spectrogram(data, fs, window, nperseg, noverlap)
    plot_fft_magnitude(data, fs)

    # 调整布局
    plt.tight_layout()

    # 显示图形
    plt.show()


#!/usr/bin/env python
from Bio import SeqIO
import argparse
import json
import os
from CPT_GFFParser import gffParse, gffWrite

def parse_xmfa(xmfa):
    """Simple XMFA parser until https://github.com/biopython/biopython/pull/544
    """
    current_lcb = []
    current_seq = {}
    for line in xmfa.readlines():
        if line.startswith("#"):
            continue

        if line.strip() == "=":
            if "id" in current_seq:
                current_lcb.append(current_seq)
                current_seq = {}
            yield current_lcb
            current_lcb = []
        else:
            line = line.strip()
            if line.startswith(">"):
                if "id" in current_seq:
                    current_lcb.append(current_seq)
                    current_seq = {}
                data = line.strip().split()
                # 0 1           2 3      4 5
                # > 1:5986-6406 + CbK.fa # CbK_gp011
                id, loc = data[1].split(":")
                start, end = loc.split("-")
                current_seq = {
                    "rid": "_".join(data[1:]),
                    "id": id,
                    "start": int(start),
                    "end": int(end),
                    "strand": 1 if data[2] == "+" else -1,
                    "seq": "",
                    "comment": "",
                }
                if len(data) > 5:
                    current_seq["comment"] = " ".join(data[5:])
            # else:
            # current_seq['seq'] += line.strip()

def percent_identity(a, b):
    """Calculate % identity, ignoring gaps in the host sequence
    """
    match = 0
    mismatch = 0
    for char_a, char_b in zip(list(a), list(b)):
        if char_a == "-":
            continue
        if char_a == char_b:
            match += 1
        else:
            mismatch += 1

    if match + mismatch == 0:
        return 0.0
    return 100 * float(match) / (match + mismatch)

def get_fasta_ids(sequences):
    """Returns a list of fasta records in the order they appear
    """
    ids = []
    for seq in SeqIO.parse(sequences, "fasta"):
        ids.append(seq.id)
    return ids

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="parse xmfa file")
    parser.add_argument("gff3", type=argparse.FileType("r"), help="Multi-GFF3 File")
    parser.add_argument("fasta", type=argparse.FileType("r"), help="Multi-FA file")
    parser.add_argument("xmfa", type=argparse.FileType("r"), help="XMFA File")
    parser.add_argument("output_dir", type=str, help="output directory")
    args = parser.parse_args()

    fasta_list = get_fasta_ids(args.fasta)
    lcbs = parse_xmfa(args.xmfa)

    if not os.path.exists(args.output_dir):
        os.makedirs(args.output_dir)

    output = {"fasta": [], "gff3": [], "xmfa": None}

    processed_xmfa = os.path.join(args.output_dir, "regions.json")
    with open(processed_xmfa, "w") as handle:
        json.dump([lcb for lcb in lcbs if len(lcb) > 1], handle, sort_keys=True)

    output["xmfa"] = processed_xmfa

    # Have to seek because we already access args.fasta once in id_tn_dict
    args.fasta.seek(0)
    # Load up sequence(s) for GFF3 data
    seq_dict = SeqIO.to_dict(SeqIO.parse(args.fasta, "fasta"))
    # Parse GFF3 records
    gffs = gffParse(args.gff3, base_dict=seq_dict)
    for record in sorted(gffs, key=lambda rec: fasta_list.index(rec.id)):
        gff_output = os.path.join(args.output_dir, record.id + ".gff")
        with open(gff_output, "w") as handle:
            gffWrite([record], handle)
        output["gff3"].append(gff_output)

        fa_output = os.path.join(args.output_dir, record.id + ".txt")
        with open(fa_output, "w") as handle:
            handle.write(str(record.seq))
            output["fasta"].append(
                {"path": fa_output, "length": len(record.seq), "name": record.id}
            )

    print(json.dumps(output, sort_keys=True))


import random
import sys
from pyfiglet import Figlet
import requests
import json
import os
from dotenv import load_dotenv

# Setting up TMDB API Key

load_dotenv()
API_KEY = os.getenv('TMDB_API_KEY')

# Retrieve top rated movies in TheMovieDB

pages = {'results': []}
for i in range(5):
    page = requests.get(f'https://api.themoviedb.org/3/movie/top_rated?api_key={API_KEY}&language=en-US&page={i+1}').json()
    pages['results'].extend(page['results'])

# Create a list that will contain the names of the movies to be guessed by the player

list_of_movies = []

for result in pages['results']:
    if result['original_language'] == 'en' and len(result['title']) < 40:
        list_of_movies.append(result['title'].strip())

# Setting up header font

figlet = Figlet()
fonts = figlet.getFonts()
figlet.setFont(font='ogre')
def main():
    print(figlet.renderText('Welcome to\n Movie\n Hangman!'))

    while True:
        user_input = input('Press s to start a new game or e to exit: ').strip()
        try:
            start = start_new_game(user_input)
        except ValueError:
            print('Invalid input')
            continue
        else:
            if start:
                movie_to_guess = get_movie(list_of_movies)
                game(movie_to_guess)
            else:
                sys.exit()

# Checks user input on the main screen to start a new game, exit the program or ask for input again if it was not valid

def start_new_game(play):
    if play.lower() == "s":
        print("Good luck!")
        return True
    elif play.lower() == "e":
        print("Ok. Goodbye!")
        return False
    else:
        raise ValueError('Invalid input')

# Selects a random movie from the list if available movies

def get_movie(list_of_movies):
    return random.choice(list_of_movies)

# Returns a list containing a '_' for each letter in the movie to guess

def hide_movie(movie):
    hidden_movie = ['_' if letter.isalpha() else letter for letter in movie]
    return hidden_movie

# Starts up a game of Hangman.

def game(title):

    hidden_movie = hide_movie(title) # a list containing a '_' for each letter in the movie to guess
    movie = title # name of the movie to be guessed as a string
    number_of_guesses = 8 # number of tries that the player has left.

    print(f'Your movie contains {hidden_movie.count("_")} letters.')
    print(' '.join(hidden_movie))

    # The following block will run while the player has guesses left. It will be interrupted if the player
    # guesses the correct word before running out of guesses.

    while number_of_guesses > 0:

        # As long as there are any '_' remaining in hidden_movie , the player will be asked to make a guess.

        if '_' in hidden_movie:

            print(f"You have {number_of_guesses} {'guess' if number_of_guesses == 1 else 'guesses'} left")
            user_guess = input('Enter a letter:').lower().strip()
            result = play_round(user_guess, movie, hidden_movie)
            if result is None:
                print(' '.join(hidden_movie))
                continue
            elif result:
                # If the player's guess was correct, any '_' in hidden_movie will be replaced with the correct letter
                indices = [i for i, x in enumerate(movie) if x.lower() == user_guess]
                for index in indices:
                    hidden_movie[index] = movie[index]
                print(' '.join(hidden_movie))
            else:
                number_of_guesses -= 1
                print(' '.join(hidden_movie))

        # If there aren't any '_' left in hidden_movie it means that all the letters have been
        # discovered and the player has won.

        else:
            print('You win!')
            break

    # If the player doesn't have any guesses left, a message including the correct word is shown.

    if number_of_guesses == 0:
        print(f"You Lose! The movie was {movie}")

def play_round(guess, title, hidden_title):

    if len(guess) != 1 or not guess.isalpha() :
        print('Invalid input. Please enter a letter')
        return None

    elif guess in hidden_title or guess.upper() in hidden_title:
        print('You already guessed this letter. Try a different one')
        return None

    elif guess in title.lower():
        print('Correct!')
        return True

    elif guess not in title.lower():
        print('Wrong! Try again!')
        return False

if __name__ == '__main__':
    main()


import bottle
import json
import random

from . import DatabaseManager
from .product import Product
import recommender.vector.arithmetic
import recommender.rocchio.algorithm

@bottle.route('/product/get/<doc_id:int>')
def product_get(doc_id):
    d = product_manager.get_product(doc_id).as_dictionary()
    result = {'result': d}
    return result

@bottle.route('/product/remove/<doc_id:int>', method='DELETE')
def product_remove(doc_id):
    try:
        product_manager.remove_document(doc_id)
    except:
        return {'result': False}
    return {'result': True}

@bottle.route('/product/all')
def product_get_all():
    l = [ p.as_dictionary() for p in product_manager.get_all_products()]
    result = {'result': l}
    #bottle.response.content_type = 'application/json'
    return result

@bottle.route('/product/random/<count:int>')
def product_random(count):
    products = product_manager.get_all_products()
    rands = []
    while len(rands) < count:
        index = random_generator.randint(0, len(products)-1)

        rands.append(products[index].as_dictionary())

        products.remove(products[index])
        pass
    result = {'result': rands};
    return result

@bottle.route('/product/insert', method='POST')
def product_insert():
    """
    curl -X POST -d "product={'image_name':'img.jpg','terms':{'a':1,'b':3}}"
    """
    try:
        product_json = bottle.request.forms.get('product')
        product_dict = json.loads(product_json)

        p = Product()
        p.image_name = product_dict['image_name']
        p.terms = product_dict['terms']

        product_manager.add_document(p)
    except:
        return {'result': False}
    return {'result': True}

@bottle.route('/vector/default/<doc_id:int>')
def vector_default(doc_id):
    d = (product_vector_manager
        .get_vector_for_document_id(doc_id)
        .as_dictionary()
        )
    result = {'result': d}
    return result

@bottle.route('/vector/df')
def vector_df():
    d = (
        product_vector_manager
        .get_document_frequency_vector()
        .as_dictionary()
    )
    result = {'result': d}
    return result

@bottle.route('/vector/idf')
def vector_idf():
    d = (
        product_vector_manager
        .get_inverse_document_frequency_vector()
        .as_dictionary()
    )
    result = {'result': d}
    return result

@bottle.route('/vector/tf/<doc_id:int>')
def vector_tf(doc_id):
    d = (
        product_vector_manager
        .get_term_frequency_vector(doc_id)
        .as_dictionary()
    )
    result = {'result': d}
    return result

@bottle.route('/vector/tfidf/<doc_id:int>')
def vector_tfidf(doc_id):
    d = (
        product_vector_manager
        .get_tfidf_vector(doc_id)
        .as_dictionary()
    )
    result = {'result': d}
    return result

@bottle.route('/vector/user/<user_id:int>')
def vector_user_by_id(user_id):
    d = (
        user_vector_manager
            .get_user_vector_for_id(user_id)
            .as_dictionary()
    )
    result = {'result': d}
    return result

@bottle.route('/vector/user/<user_name>')
def vector_user_by_name(user_name):
    d = (
        user_vector_manager
            .get_user_vector_for_name(user_name)
            .as_dictionary()
    )
    result = {'result': d}
    return result

@bottle.route('/user/all')
def get_all_users():
    user_list = user_vector_manager.get_all_users_by_name()
    result = {'result': user_list}
    return result

@bottle.route('/user/create/<user_name>')
def create_user_by_name(user_name):
    user_vector_manager.create_user(user_name)
    return {'result': True}

@bottle.route('/user/exists/<user_name>')
def exists_user_by_name(user_name):
    d = {}
    d['exists'] = user_vector_manager.has_user_with_name(user_name)
    result = {'result': d}
    return result

@bottle.route('/user/remove/<user_name>', method='DELETE')
def remove_user_by_name(user_name):
    try:
        user_id = user_vector_manager.get_user_id_for_name(user_name)
        user_vector_manager.remove_user(user_id)
    except:
        return {'result': False}
    return {'result': True}

@bottle.route('/user/createifnotexist/<user_name>')
def create_user_if_not_exists(user_name):
    if not user_vector_manager.has_user_with_name(user_name):
        create_user_by_name(user_name)
    return {'result': True}

@bottle.route('/user/setpreference/<user_name>/<product_id:int>')
def add_preference_to_user(user_name, product_id):
    user_id = user_vector_manager.get_user_id_for_name(user_name)
    user_vector_manager.set_user_preference(user_id, product_id, True)
    return {'result': True}

@bottle.route('/user/setnopreference/<user_name>/<product_id:int>')
def add_preference_to_user(user_name, product_id):
    user_id = user_vector_manager.get_user_id_for_name(user_name)
    user_vector_manager.set_user_preference(user_id, product_id, False)
    return {'result': True}

@bottle.route('/user/update/<user_name>')
def get_user_update(user_name):
    user_id = user_vector_manager.get_user_id_for_name(user_name)

    weights = recommender.rocchio.default_weights()

    update_user(user_id, weights)

    return {'result': True}

@bottle.route('/user/update/<user_name>/<alpha:int>/<beta:int>/<gamma:int>')
def get_user_update(user_name, alpha, beta, gamma):
    user_id = user_vector_manager.get_user_id_for_name(user_name)

    if alpha < 0:
        alpha = 0
    elif alpha > 100:
        alpha = 100;
    if beta < 0:
        beta = 0
    elif beta > 100:
        beta = 100
    if gamma < 0:
        gamma = 0
    elif gamma > 100:
        gamma = 100

    weights = alpha / 100, beta / 100, gamma / 100

    update_user(user_id, weights)
    return {'result': True}

@bottle.route('/user/relevant/<user_name>')
def get_user_preference(user_name):
    user_id = user_vector_manager.get_user_id_for_name(user_name)
    relevant_vectors = user_vector_manager.get_relevant_document_vector_list(user_id)
    relevant_products = [
        product_manager.get_product(v.document_id).as_dictionary()
        for v in relevant_vectors
    ]

    result = {'result': relevant_products}
    return result

@bottle.route('/user/nonrelevant/<user_name>')
def get_user_no_preference(user_name):
    user_id = user_vector_manager.get_user_id_for_name(user_name)
    non_relevant_vectors = user_vector_manager.get_non_relevant_document_vector_list(user_id)
    non_relevant_products = [
        product_manager.get_product(v.document_id).as_dictionary()
        for v in non_relevant_vectors
    ]

    result = {'result': non_relevant_products}
    return result

@bottle.route('/recommendations/<user_name>/<k:int>')
def get_recommendation(user_name, k):
    vector = user_vector_manager.get_user_vector_for_name(user_name)
    others = product_vector_manager.get_all_vectors()

    #distance_function = recommender.vector.arithmetic.hamming_distance
    #distance_function = recommender.vector.arithmetic.euclidean_distance

    recommendations = vector_arithmetic.k_nearest_neighbours(k, vector, others)
    products = [
        product_manager.get_product(vector.document_id).as_dictionary()
        for _, vector in recommendations
    ]
    result = {'result': products}
    return result

database_manager = None
product_manager = None
product_vector_manager = None
document_manager = None
user_vector_manager = None
term_manager = None

random_generator = None

vector_arithmetic = recommender.vector.arithmetic

def run(database_path, host, port):
    _init(database_path)
    bottle.run(host=host, port=port, debug=True)

def _init(database_path):
    global database_manager
    global product_manager
    global product_vector_manager
    global document_manager
    global user_vector_manager
    global term_manager

    global random_generator

    database_manager = DatabaseManager(database_path)
    product_manager = database_manager.get_product_manager()
    product_vector_manager = database_manager.get_product_vector_manager()
    document_manager = database_manager.get_document_manager()
    user_vector_manager  = database_manager.get_user_vector_manager()
    term_manager = database_manager.get_term_manager()

    random_generator = random.Random()

def update_user(user_id, weights):
    user_vector = user_vector_manager.get_user_vector_for_id(user_id)
    relevant = user_vector_manager.get_relevant_document_vector_list(user_id)
    non_relevant = user_vector_manager.get_non_relevant_document_vector_list(user_id)

    uvector = recommender.rocchio.algorithm.calculate(user_vector, relevant, non_relevant, weights)
    user_vector_manager.update_user_vector(user_id, uvector);
    pass


import os
import sys

if not "DEVITO_OPENMP" in os.environ or os.environ["DEVITO_OPENMP"] != "1":
    print("*** WARNING: Devito OpenMP environment variable has not been set ***", file=sys.stderr)

import numpy as np
from sympy import Matrix, Eq, solve
import progressbar
from devito import TimeData, Operator, t, x, y, z, logger as devito_logger, parameters as devito_parameters

from . import sim

devito_logger.set_log_level('WARNING')

def vector_laplacian(u):
    return Matrix([u[0].dx2 + u[0].dy2 + u[0].dz2,
                   u[1].dx2 + u[1].dy2 + u[1].dz2,
                   u[2].dx2 + u[2].dy2 + u[2].dz2])

def vector_gradient(u):
    return u[0].dx**2 + u[0].dy**2 + u[0].dz**2 + u[1].dx**2 + u[1].dy**2 + u[1].dz**2 + u[2].dx**2 + u[2].dy**2 + u[2].dz**2

def curl(u):
    return Matrix([u[2].dy - u[1].dz,
                   u[0].dz - u[2].dx,
                   u[1].dx - u[0].dy])

expression_cache = {}

class Sim(sim.Sim):

    framework_name = "Devito"

    @property
    def data_shape(self):
        # Devito doesn't like numpy types for the grid dimensions, and it needs to be a tuple, so shape needs to be converted
        return tuple(int(i) for i in self.grid_params.n)

    def data_matrix(self, settings):
        return Matrix([TimeData(name='m_x', **settings),
            TimeData(name='m_y', **settings),
            TimeData(name='m_z', **settings)])

    def generate_step_kernel(self):
        settings = {"shape":self.buffer_dims, "space_order":2}
        m = self.data_matrix(settings)
        c = 2 / (self.mu0 * self.sim_params.Ms)
        zeeman = Matrix(self.sim_params.H)
        exchange = self.sim_params.A * c * vector_laplacian(m)
        e = Matrix(self.sim_params.e)
        anisotropy = self.sim_params.K * c * m.dot(e) * e
        dmi = self.sim_params.D * c * curl(m)
        heff = zeeman + exchange + anisotropy + dmi
        crossHeff = m.cross(heff)
        dmdt_rhs = -self.gamma0 / (1 + self.sim_params.alpha**2) * (crossHeff + self.sim_params.alpha * m.cross(crossHeff))
        dmdt_lhs = Matrix([TimeData(name='dmdt_x', **settings),
            TimeData(name='dmdt_y', **settings),
            TimeData(name='dmdt_z', **settings)])
        dmdt_correction = self.correction * dmdt_lhs.dot(dmdt_lhs)**0.5 * (1 - m.dot(m)) * m
        string_llg = str(dmdt_rhs) + str(dmdt_correction)

        if string_llg in expression_cache:
            update = expression_cache[string_llg]
        else:
            update = []
            if self.correction > 0:
                # if using correction solve in 2 steps; calculate dmdt, then calculate m[t+1] = dmdt + correction
                for i, dmdti in enumerate(dmdt_lhs):
                    update.append(Eq(dmdti, dmdt_rhs[i]))
                llg_eqn = Matrix([mi.dt for mi in m]) - (dmdt_lhs + dmdt_correction)
            else:
                # if not using correction; m[t+1] = dmdt
                llg_eqn = Matrix([mi.dt for mi in m]) - dmdt_rhs

            print("Solving LLG Sympy expressions ...", file=sys.stderr)
            with progressbar.ProgressBar(max_value=len(m)) as bar:
                for i, mi in enumerate(m):
                    update.append(Eq(mi.forward, solve(llg_eqn[i], mi.forward)[0]))
                    bar.update(i + 1)
            expression_cache[string_llg] = update

        bcs = []
        nx, ny, nz = self.buffer_dims
        if self.periodic_boundary:
            for mi in m:
                bcs += [Eq(mi.indexed[t, x, y, 0], mi.indexed[t, x, y, nz - 2])]
                bcs += [Eq(mi.indexed[t, x, y, nz - 1], mi.indexed[t, x, y, 1])]
                bcs += [Eq(mi.indexed[t, x, 0, z], mi.indexed[t, x, ny - 2, z])]
                bcs += [Eq(mi.indexed[t, x, ny - 1, z], mi.indexed[t, x, 1, z])]
                bcs += [Eq(mi.indexed[t, 0, y, z], mi.indexed[t, nx - 2, y, z])]
                bcs += [Eq(mi.indexed[t, nx - 1, y, z], mi.indexed[t, 1, y, z])]
        else:
            for mi in m:
                bcs += [Eq(mi.indexed[t, x, y, 0], 0.)]
                bcs += [Eq(mi.indexed[t, x, y, nz - 1], 0.)]
                bcs += [Eq(mi.indexed[t, x, 0, z], 0.)]
                bcs += [Eq(mi.indexed[t, x, ny - 1, z], 0.)]
                bcs += [Eq(mi.indexed[t, 0, y, z], 0.)]
                bcs += [Eq(mi.indexed[t, nx - 1, y, z], 0.)]

        dx, dy, dz = self.grid_params.d
        dt = self.time_params.d
        subs = {x.spacing: dx, y.spacing: dy, z.spacing: dz, t.spacing: dt}
        op = Operator(bcs + update, subs=subs)

        # Call op trigger compilation
        op(time=1)

        def step(f, t):
            for i, mi in enumerate(m):
                mi.data[(0, ) + self.buffer_slice] = f[i]
            op(time=self.save_every + 1)
            for i, mi in enumerate(m):
                t[i] = mi.data[(self.save_every % 2, ) + self.buffer_slice]

        return step

"""
    def energy_expr(self, m):
        dV = self.grid_params.prod_d
        e = Matrix(self.sim_params.e)
        H = Matrix(self.sim_params.H)
        Kc = dV * -self.sim_params.K
        Ac = dV * self.sim_params.A
        Dc = dV * -self.sim_params.D
        Hc = dV * -self.mu0 * self.sim_params.Ms

        return {"Zeeman":Hc * m.dot(H),
            "Exchange":Ac * vector_gradient(m),
            "Anisotropy":Kc * (m.dot(e))**2,
            "DMI":Dc * m.dot(curl(m))}
    def generate_energy_kernel(self):
        settings = {"shape":self.buffer_dims, "space_order":2}
        m = self.data_matrix(settings)
        energy_expr = self.energy_expr(m)
        E = TimeData(name='E', **settings)
        eqn = Eq(E, sum(energy_expr.values()))
        dx, dy, dz = self.grid_params.d
        subs = {x.spacing: dx, y.spacing: dy, z.spacing: dz}
        # turn dle off because some eqns are 1st and some are 2nd order, requiring different bounds.
        op = Operator(eqn, subs=subs, dle=False)

        # Call op trigger compilation
        op()

        def energy(d):
            for i, mi in enumerate(m):
                mi.data[0] = d[i]
            op(time=1)
            return E.data[0]

        return energy

    def generate_detailed_energy_kernel(self, terms):
        def energy(d):
            settings = {"shape":self.buffer_dims, "space_order":2, "time_dim":len(d), "save":True}
            m = self.data_matrix(settings)
            energy_expr = self.energy_expr(m)

            names = [k for k in terms if k in energy_expr]
            symbols = []
            eqns = []
            for key in names:
                symbol = TimeData(name='E_{}'.format(key), **settings)
                symbols.append(symbol)
                eqns.append(Eq(symbol, energy_expr[key]))

            dx, dy, dz = self.grid_params.d
            subs = {x.spacing: dx, y.spacing: dy, z.spacing: dz}
            # turn dle off because some eqns are 1st and some are 2nd order, requiring different bounds.
            op = Operator(eqns, subs=subs, dle=False)

            for i, mi in enumerate(m):
                for j, dj in enumerate(d):
                    mi.data[j] = dj[i]
            op()
            ret = {}
            for i, name in enumerate(names):
                ret[name] = []
                for dj in symbols[i].data:
                    ret[name].append(dj)
            return ret

        return energy
"""


# @PascalPuchtler

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================

import json
import time
from sys import platform
import serial

class MoveControllerCommunication:
    def __init__(self,carModel, com = None, baudrate= 9600, changeMoveCallback = None):
        self.radiusBig = 0.55
        self.radiusSmall = 0.365
        self.error = False
        self.carModel = carModel
        self.changeMoveCallback = changeMoveCallback
        if com is None:
            if platform == "win32":
                com = 'COM7'
            else:
                com ='/dev/ttyACM0'
        try:
            self.communication = serial.Serial(com, baudrate= 9600,
            timeout=2.5,
            parity=serial.PARITY_NONE,
            bytesize=serial.EIGHTBITS,
            stopbits=serial.STOPBITS_ONE)

            time.sleep(1)
            self.communication.reset_input_buffer()
        except:
            print('Error: No Move controller available over port ' + com)
            self.error = True

    def turnLeft(self):
        self.driveCircle(self.radiusSmall,True, True)

    def turnRight(self):
        self.driveCircle(self.radiusSmall,True, False)

    def drive(self):
        self.driveCircle(float('inf'),True, False)

    def driveLeft(self):
        self.driveCircle(self.radiusBig,True, True)

    def driveRight(self):
        self.driveCircle(self.radiusBig,True, False)

    def backwardLeft(self):
        self.driveCircle(self.radiusBig,False, True)

    def backwardRight(self):
        self.driveCircle(self.radiusBig,False, False)

    def backward(self):
        self.driveCircle(float('inf'), False, False)

    def stop(self):
        if self.changeMoveCallback is not None:
            self.changeMoveCallback(0, 0)
        self.move([0,0])

    def fullLeft(self):
        self.move([-100,100])
        time.sleep(0.2)
        self.stop()

    def driveCircle(self,  radius, forward, left):
        motor, gear, speed = self.carModel.getMotorSpeedFromRadius(radius, forward, left)
        print('l:', round(motor[0]), 'r:', round(motor[1]), 'g:', round(gear,4), 's:', round(speed,4))
        if self.changeMoveCallback is not None:
            self.changeMoveCallback(gear, speed)
        self.move(motor)

    def move(self, motor):
        if not self.error:
            command = {}
            command["command"] = "move"
            command["left"] = int(motor[0])
            command["right"] = int(motor[1])
            self.communication.write(json.dumps(command).encode('ascii'))

    def getSonic(self):
        if not self.error:
            inputBuffer = self.communication.readline()

            command = {}
            command["command"] = "sonic"
            self.communication.write(json.dumps(command).encode('ascii'))
            try:
                sonic = json.loads(inputBuffer)
                return sonic
            except:
                print("exception in get Sonic")
                return {"left": 0, "right": 0, "middle":0}


import logging
from asyncio import CancelledError, Task, create_task
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager, suppress

from fastapi import FastAPI
from servicelib.logging_utils import log_context
from watchdog.observers.api import DEFAULT_OBSERVER_TIMEOUT

from ._context import OutputsContext
from ._event_filter import EventFilter
from ._event_handler import EventHandlerObserver
from ._manager import OutputsManager

_logger = logging.getLogger(__name__)

class OutputsWatcher:
    def __init__(
        self, *, outputs_manager: OutputsManager, outputs_context: OutputsContext
    ) -> None:
        self.outputs_manager = outputs_manager
        self.outputs_context = outputs_context

        self._task_events_worker: Task | None = None
        self._event_filter = EventFilter(outputs_manager=outputs_manager)
        self._observer_monitor: EventHandlerObserver = EventHandlerObserver(
            outputs_context=self.outputs_context,
            outputs_manager=self.outputs_manager,
            heart_beat_interval_s=DEFAULT_OBSERVER_TIMEOUT,
        )

    async def _worker_events(self) -> None:
        while True:
            event: str | None = (
                await self.outputs_context.port_key_events_queue.coro_get()
            )
            if event is None:
                break

            await self._event_filter.enqueue(event)

    async def enable_event_propagation(self) -> None:
        await self.outputs_context.toggle_event_propagation(is_enabled=True)

    async def disable_event_propagation(self) -> None:
        await self.outputs_context.toggle_event_propagation(is_enabled=False)

    async def start(self) -> None:
        with log_context(_logger, logging.INFO, f"{OutputsWatcher.__name__} start"):
            self._task_events_worker = create_task(
                self._worker_events(), name="outputs_watcher_events_worker"
            )

            await self._event_filter.start()
            await self._observer_monitor.start()

    async def shutdown(self) -> None:
        """cleans up spawned tasks which might be pending"""
        with log_context(_logger, logging.INFO, f"{OutputsWatcher.__name__} shutdown"):
            await self._event_filter.shutdown()
            await self._observer_monitor.stop()

            if self._task_events_worker is not None:
                self._task_events_worker.cancel()
                with suppress(CancelledError):
                    await self._task_events_worker

def setup_outputs_watcher(app: FastAPI) -> None:
    async def on_startup() -> None:
        assert isinstance(app.state.outputs_context, OutputsContext)  # nosec
        outputs_context: OutputsContext = app.state.outputs_context
        outputs_manager: OutputsManager
        outputs_manager = app.state.outputs_manager  # nosec

        app.state.outputs_watcher = OutputsWatcher(
            outputs_manager=outputs_manager,
            outputs_context=outputs_context,
        )
        await app.state.outputs_watcher.start()
        await disable_event_propagation(app)

    async def on_shutdown() -> None:
        outputs_watcher: OutputsWatcher | None = app.state.outputs_watcher
        if outputs_watcher is not None:
            await outputs_watcher.shutdown()

    app.add_event_handler("startup", on_startup)
    app.add_event_handler("shutdown", on_shutdown)

async def disable_event_propagation(app: FastAPI) -> None:
    outputs_watcher: OutputsWatcher | None = app.state.outputs_watcher
    if outputs_watcher is not None:
        await outputs_watcher.disable_event_propagation()

async def enable_event_propagation(app: FastAPI) -> None:
    outputs_watcher: OutputsWatcher | None = app.state.outputs_watcher
    if outputs_watcher is not None:
        await outputs_watcher.enable_event_propagation()

@asynccontextmanager
async def event_propagation_disabled(app: FastAPI) -> AsyncGenerator[None, None]:
    try:
        await disable_event_propagation(app)
        yield None
    finally:
        await enable_event_propagation(app)


#!/usr/bin/env python
# encoding: utf-8
# @Time : 2019-07-31 10:24

__author__ = 'Ted'

from PIL import Image, ImageFont, ImageDraw

content={
    "back_img":"pre/paper.jpg",
    "001":{
        "ad":'老板，买10盒月饼呗',
        "head":'001.jpg'
    },
    "002": {
        "ad": '老板，买20盒月饼呗',
        "head": '002.jpg'
    },
    "003": {
        "ad": '老板，生活不易，买50盒月饼呗',
        "head": '003.jpg'
    },
    "004": {
        "ad": '老板，买个80盒月饼，不多',
        "head": '004.jpg'
    },
    "005": {
        "ad": '老板，看面相，你应该买100盒月饼',
        "head": '005.jpg'
    },
    "006": {
        "ad": '老板，恭喜你中奖了，奖品是150盒月饼',
        "head": '006.jpg'
    },
    "007": {
        "ad": '老板，你的员工让我告诉你，他们想吃月饼了',
        "head": '007.jpg'
    },
    "008": {
        "ad": '老板，我卖月饼，买200盒呗',
        "head": '008.jpg'
    },
    "009": {
        "ad": '老板，不整500盒月饼送礼啊',
        "head": '009.jpg'
    }
}
def get_pic(background,head,adcontent,mark,pic_name):
    im = Image.open(background)

    head_img = Image.open(f"head/{head}").resize((150,150),Image.ANTIALIAS)
    im.paste(head_img,(75,20))
    draw = ImageDraw.Draw(im)
    fnt = ImageFont.truetype("pre/SimSun.ttf",20)

    ad_parts = adcontent.split("，")
    y_pos = 180
    for ad_part in ad_parts:
        if ad_part!=ad_parts[-1]:
            ad_w,ad_h = draw.textsize(ad_part+"，", font=fnt)
            draw.text(((300-ad_w)/2,y_pos),ad_part+"，",font=fnt,fill=(0,0,0))
            y_pos+=ad_h+10
        else:
            ad_w, ad_h = draw.textsize(ad_part, font=fnt)
            draw.text(((300 - ad_w) / 2, y_pos), ad_part, font=fnt, fill=(0, 0, 0))
            y_pos += ad_h + 10

    mark_font = ImageFont.truetype("pre/arial.ttf",100)
    draw.text((125,400),mark,font=mark_font,fill=(0,0,0))

    haha = Image.open("pre/haha.jpg")
    im.paste(haha,(0,650))

    qrcode = Image.open("pre/tedxpy.jpg").resize((80,80),Image.ANTIALIAS)
    im.paste(qrcode,(180,810))
    sign_font = ImageFont.truetype("pre/SimSun.ttf",10)
    draw.text((60,875),"自定义制作图片，请扫码",font=sign_font,fill=(0,0,0))
    im.save(pic_name)

if __name__== "__main__":
    for i in range(1,10):
        background = "pre/paper.jpg"
        head = content[f'00{i}']['head']
        adcontent = content[f'00{i}']['ad']
        get_pic(background,head,adcontent,f"{i}",f"{i}.jpg")
    print("九宫格图片生成完毕！")


from __future__ import annotations

from dataclasses import fields
from typing import Tuple

import numpy as np
from napari.layers import Image

def update_layer_contrast_limits(
    layer: Image,
    contrast_limits_quantiles: Tuple[float, float] = (0.01, 0.98),
    contrast_limits_range_quantiles: Tuple[float, float] = (0.0, 1.0),
) -> None:
    nonzero_mask = layer.data > 0
    if (~nonzero_mask).all():
        return

    limit_0, limit_1, limit_range_0, limit_range_1 = np.quantile(
        layer.data[nonzero_mask],
        (*contrast_limits_quantiles, *contrast_limits_range_quantiles),
    )
    layer.contrast_limits = (limit_0, limit_1 + 1e-8)
    layer.contrast_limits_range = (limit_range_0, limit_range_1 + 1e-8)

def array_safe_eq(a, b) -> bool:
    """Check if a and b are equal, even if they are numpy arrays"""
    if a is b:
        return True
    if isinstance(a, np.ndarray) and isinstance(b, np.ndarray):
        return a.shape == b.shape and (a == b).all()
    try:
        return a == b
    except TypeError:
        return NotImplemented

def dataclass_eq(dc1, dc2) -> bool:
    """checks if two dataclasses which hold numpy arrays are equal"""
    if dc1 is dc2:
        return True
    if dc1.__class__ is not dc2.__class__:
        return NotImplemented
    fields_names = [f.name for f in fields(dc1)]
    return all(
        array_safe_eq(getattr(dc1, field_name), getattr(dc2, field_name))
        for field_name in fields_names
    )