from flask import jsonify, make_response
from app import application, db
from flask import request, render_template, redirect, url_for
from .models import UserSystemInfo, SuccessfulInstalls, FailedInstalls, Attempts
from .limiter import *
from collections import Counter
import uuid
import datetime
import operator
import json

@application.errorhandler(500)
def internal_error(error):
    db.session.rollback()

@application.route('/installation_data/', methods=['POST'])
@ratelimit(limit=500, per=60 * 60)
def installation_data():
    """
    This endpoint accepts the data from installation test scripts and stores it on the database.
    """

    user_system_info = request.json.get('user_system_info')
    successful_installs = request.json.get('successful_installs')
    failed_installs = request.json.get('failed_installs')
    unique_user_id = request.json.get('unique_user_id')

    # Check whether the unique_user_id is received in the request or not.
    # If not, generate a new id.
    if unique_user_id is None:
        unique_user_id = str(uuid.uuid4())
        message = "new id generated"
        user_info = UserSystemInfo.query.filter_by(unique_user_id=unique_user_id).first()
        while(user_info):  # Resolving Collision
            unique_user_id = str(uuid.uuid4())
            user_info = UserSystemInfo.query.filter_by(unique_user_id=unique_user_id).first()
    else:
        message = "pushed data with same id"

        # Check whether the received unique id has already an associated record
        # in the database, or is it accidently changed by the user.
        user_info = UserSystemInfo.query.filter_by(unique_user_id=unique_user_id).first()
        if user_info is None:
            unique_user_id = str(uuid.uuid4())
            message = "new id generated"

    # Get the system information from 'user_system_info', a dictionary received in the request.
    distribution_name = user_system_info.get('distribution_name')
    distribution_version = user_system_info.get('distribution_version')
    system_version = user_system_info.get('system_version')
    system = user_system_info.get('system')
    machine = user_system_info.get('machine')
    system_platform = user_system_info.get('system_platform')
    python_version = user_system_info.get('python_version')
    workshop_id = user_system_info.get('workshop_id')
    email_id = user_system_info.get('email_id')
    # uname  = user_system_info.get('uname')
    workshop_id_default = "No workshop name provided"

    # Everytime an attempt is made, be it from a new user, or from the same user,
    # log the attempt with the user's unique_user_id
    attempt = Attempts(unique_user_id=unique_user_id)

    # Create lists of objects for failed and succesfully installed packages, so that they can be added
    # using the user_id as foreign key.
    success_objects_list = [
        SuccessfulInstalls(name=succ_install.get('name'), version=succ_install.get('version').replace('\n', ''))
        for succ_install in successful_installs
    ]

    failed_objects_list = [
        FailedInstalls(name=fail_install.get('name'), version=fail_install.get('version').replace('\n', ''),
                       error_description=fail_install.get('error_description'))
        for fail_install in failed_installs
    ]

    # Check whether their already exists a record with this unique_user_id.
    # If yes, update the information, else, create a new record.
    user_info = UserSystemInfo.query.filter_by(unique_user_id=unique_user_id).first()
    if user_info is None:
        if workshop_id is None:
            workshop_id = workshop_id_default
        user_info = UserSystemInfo(distribution_name=distribution_name,
                                   distribution_version=distribution_version, system_version=system_version,
                                   system=system, machine=machine, system_platform=system_platform,
                                   workshop_id=workshop_id, email_id=email_id,
                                   python_version=python_version, unique_user_id=unique_user_id)
    else:  # Update anyway
        user_info.distribution_name = distribution_name
        user_info.distribution_version = distribution_version
        user_info.system_version = system_version
        user_info.system = system
        user_info.machine = machine
        user_info.system_platform = system_platform

        # email_id and workshop_id are updated only when these fields are not None in the request.
        # As otherwise None will be overwritten to previously added workshop_id and email_id in case of
        # second attempt.
        if email_id is not None:
            user_info.email_id = email_id
        if workshop_id is not None:
            user_info.workshop_id = workshop_id
        user_info.python_version = python_version
        user_info.unique_user_id = unique_user_id

    # Add the objects list created above to user_info and attempt objects
    # to reference the foreign key for both.
    user_info.successful_installs.extend(success_objects_list)
    user_info.failed_installs.extend(failed_objects_list)
    attempt.successful_installs.extend(success_objects_list)
    attempt.failed_installs.extend(failed_objects_list)

    db.session.add(attempt)
    db.session.add(user_info)
    db.session.add_all(success_objects_list)
    db.session.add_all(failed_objects_list)

    try:
        db.session.commit()
    except:
        summary = {"status": "Something bad happened"}
    else:
        summary = {"status": "Successful"}

    # Return the key and message, whether a new unique_user_id was created
    # or previous unique_user_id was used.
    summary['message'] = message
    response = {'key': unique_user_id, 'summary': summary}
    return make_response(jsonify(response))

@application.route('/')
def default():
    return render_template('landing_page.html', response=None)

@application.route('/view/')
def data_view():
    """
    This endpoint returns the data for all the worlshops.
    """

    all_attempts = request.args.get('all_attempts')
    if all_attempts:
        all_attempts = int(all_attempts)
    # Select the operating system name and the count of its user using group_by 'UserSystemInfo.system'
    user_info = db.session.query(UserSystemInfo.system,
                                 db.func.count().label("count")).group_by(UserSystemInfo.system).all()
    os_users = {}
    for user in user_info:
        os_users[user.system] = user.count

    # if all attempts toggle is on, select all failed install for each attempt.
    if all_attempts:
        failed_info = db.session.query(FailedInstalls.name, FailedInstalls.version,
                                       db.func.count().label("count")).group_by(FailedInstalls.name,
                                                                                FailedInstalls.version).all()
        failed_info_names = db.session.query(FailedInstalls.name,
                                             db.func.count().label("count")).group_by(FailedInstalls.name).all()
    else:
        # select all the latest attempt_ids per unique user from attempts table
        attempts = db.session.query(db.func.max(Attempts.id)).group_by(Attempts.unique_user_id).all()
        latest_attempt_ids = [x[0] for x in attempts]

        # query failed_installs table with a filter : attempt_id in latest_attempt_ids.
        failed_info = db.session.query(
            FailedInstalls.name, FailedInstalls.version,
            db.func.count().label("count")).filter(
            FailedInstalls.attempt_id.in_(latest_attempt_ids)).group_by(
            FailedInstalls.name, FailedInstalls.version).all()

        failed_info_names = db.session.query(FailedInstalls.name, db.func.count().label("count")).filter(
            FailedInstalls.attempt_id.in_(latest_attempt_ids)).group_by(FailedInstalls.name).all()

    most_failed_packages = [
        {"name": fail.name, "version": fail.version, "count": fail.count}
        for fail in failed_info
    ]

    most_failed_package_names = [
        {"name": fail.name, "count": fail.count}
        for fail in failed_info_names
    ]

    most_failed_packages = sorted(most_failed_packages, key=lambda k: k['count'], reverse=True)
    most_failed_package_names = sorted(most_failed_package_names, key=lambda k: k['count'], reverse=True)
    os_users = sorted(os_users.items(), key=operator.itemgetter(1), reverse=True)

    user_info = db.session.query(UserSystemInfo.workshop_id.distinct().label("workshop_id")).all()
    workshops = [
        user.workshop_id for user in user_info
        if user.workshop_id is not None
    ]

    response = {
        "most_failed_packages": most_failed_packages,
        "most_failed_package_names": most_failed_package_names,
        "os_users": os_users,
        "workshops": workshops,
        "workshop_id": "All workshops",
        "all_workshops": True,
        "all_attempts": all_attempts
    }

    if request.args.get('export') == 'json':
        return make_response(jsonify(response))

    return render_template('index.html', response=response)

@application.route('/view/<workshop_id>/')
def data_view_by_workshop(workshop_id):
    """
    This endpoint returns the data for a specific workshop.
    """

    all_attempts = request.args.get('all_attempts')
    if all_attempts:
        all_attempts = int(all_attempts)
    # If All workshops is selected as an option, redirect to '/view/'
    if workshop_id == "All workshops":
        return redirect(url_for('data_view'))
    user_info = db.session.query(
        UserSystemInfo.system, db.func.count().label("count")).filter_by(
        workshop_id=workshop_id).group_by(UserSystemInfo.system).all()
    os_users = {}
    for user in user_info:
        os_users[user.system] = user.count

    # if all attempts toggle is on, select all failed install for each attempt.
    if all_attempts:
        failed_info = db.session.query(
            UserSystemInfo, FailedInstalls).add_columns(
            FailedInstalls.name, FailedInstalls.version, db.func.count().label("count")).filter(
            UserSystemInfo.id == FailedInstalls.user_id,
            UserSystemInfo.workshop_id == workshop_id).group_by(
            FailedInstalls.name, FailedInstalls.version)

        failed_info_names = db.session.query(
            UserSystemInfo, FailedInstalls).add_columns(
            FailedInstalls.name, db.func.count().label("count")).filter(
            UserSystemInfo.id == FailedInstalls.user_id,
            UserSystemInfo.workshop_id == workshop_id).group_by(FailedInstalls.name)
    else:
        # select all the latest attempt_ids per unique user from attempts table
        attempts = db.session.query(
            UserSystemInfo, Attempts).add_columns(
            db.func.max(Attempts.id).label("attempt_id")).filter(
            UserSystemInfo.unique_user_id == Attempts.unique_user_id,
            UserSystemInfo.workshop_id == workshop_id
        ).group_by(Attempts.unique_user_id)
        latest_attempt_ids = [x.attempt_id for x in attempts]

        # query failed_installs table with a filter : attempt_id in latest_attempt_ids.
        failed_info = db.session.query(
            FailedInstalls.name, FailedInstalls.version, db.func.count().label("count")).filter(
            FailedInstalls.attempt_id.in_(latest_attempt_ids)).group_by(
            FailedInstalls.name, FailedInstalls.version).all()

        failed_info_names = db.session.query(FailedInstalls.name, db.func.count().label("count")).filter(
            FailedInstalls.attempt_id.in_(latest_attempt_ids)).group_by(FailedInstalls.name).all()

    most_failed_packages = [
        {"name": fail.name, "version": fail.version, "count": fail.count}
        for fail in failed_info
    ]

    most_failed_package_names = [
        {"name": fail.name, "count": fail.count}
        for fail in failed_info_names
    ]

    most_failed_packages = sorted(most_failed_packages, key=lambda k: k['count'], reverse=True)
    most_failed_package_names = sorted(most_failed_package_names, key=lambda k: k['count'], reverse=True)
    os_users = sorted(os_users.items(), key=operator.itemgetter(1), reverse=True)

    # Get a list of all the workshops
    user_info = db.session.query(UserSystemInfo.workshop_id.distinct().label("workshop_id")).all()
    workshops = [
        user.workshop_id for user in user_info
        if user.workshop_id is not None
    ]

    response = {
        "most_failed_packages": most_failed_packages,
        "most_failed_package_names": most_failed_package_names,
        "os_users": os_users,
        "workshops": workshops,
        "all_workshops": False,
        "workshop_id": workshop_id,
        "all_attempts": all_attempts
    }

    if request.args.get('export') == 'json':
        return make_response(jsonify(response))

    return render_template('index.html', response=response)

@application.route('/view/detail/')
def data_view_detail_package():
    """
    This endpoint returns the details of the selected package(s). It returns the result
    in json as well with 'export=json' as url parameter. Results are viewed in the
    form of plots and tables on details.html
    """

    package_one_name = request.args.get('package_one_name')
    package_one_version = request.args.get('package_one_version')
    package_two_name = request.args.get('package_two_name')
    package_two_version = request.args.get('package_two_version')
    if package_one_name is None:
        return redirect(url_for('data_view'))
    if package_two_name and package_two_name == package_one_name and package_one_version == package_two_version:
        package_two_name = None
    if package_one_version == "All":  # if all versions is selected, turn the version selected to None
        package_one_version = None
    if package_two_name and package_two_name == "None":
        package_two_name = None
    if package_two_version and package_two_version == "All":
        package_two_version = None

    workshop_id = request.args.get('workshop_id')
    if workshop_id and workshop_id == "All workshops":
        workshop_id = None
    all_attempts = request.args.get('all_attempts')
    if all_attempts:
        all_attempts = int(all_attempts)
    failed_packages = [
        {
            "package_name": package_one_name,
            "version": package_one_version,
        },
        {
            "package_name": package_two_name,
            "version": package_two_version,
        }
    ]
    package_details = []
    for failed_package in failed_packages:  # iterate over the loop of 2 packages
        if not failed_package['package_name']:  # in case only 1 package is selected
            continue
        if all_attempts:
            if workshop_id:
                if not failed_package['version']:
                    user_info = db.session.query(FailedInstalls, UserSystemInfo).add_columns(
                        UserSystemInfo.distribution_name, UserSystemInfo.distribution_version,
                        UserSystemInfo.system, UserSystemInfo.system_platform,
                        UserSystemInfo.system_version, UserSystemInfo.machine,
                        UserSystemInfo.python_version, FailedInstalls.create_time).filter(
                        UserSystemInfo.id == FailedInstalls.user_id,
                        FailedInstalls.name == failed_package['package_name'],
                        UserSystemInfo.workshop_id == workshop_id
                    )
                else:
                    user_info = db.session.query(FailedInstalls, UserSystemInfo).add_columns(
                        UserSystemInfo.distribution_name, UserSystemInfo.distribution_version,
                        UserSystemInfo.system, UserSystemInfo.system_platform,
                        UserSystemInfo.system_version, UserSystemInfo.machine,
                        UserSystemInfo.python_version, FailedInstalls.create_time).filter(
                        UserSystemInfo.id == FailedInstalls.user_id,
                        FailedInstalls.name == failed_package['package_name'],
                        FailedInstalls.version == failed_package['version'],
                        UserSystemInfo.workshop_id == workshop_id
                    )
            else:
                if not failed_package['version']:
                    user_info = db.session.query(UserSystemInfo, FailedInstalls).add_columns(
                        UserSystemInfo.distribution_name, UserSystemInfo.distribution_version,
                        UserSystemInfo.system, UserSystemInfo.system_platform,
                        UserSystemInfo.system_version, UserSystemInfo.machine,
                        UserSystemInfo.python_version, FailedInstalls.create_time).filter(
                        UserSystemInfo.id == FailedInstalls.user_id,
                        FailedInstalls.name == failed_package['package_name'],
                    )
                else:
                    user_info = db.session.query(UserSystemInfo, FailedInstalls).add_columns(
                        UserSystemInfo.distribution_name, UserSystemInfo.distribution_version,
                        UserSystemInfo.system, UserSystemInfo.system_platform,
                        UserSystemInfo.system_version, UserSystemInfo.machine,
                        UserSystemInfo.python_version, FailedInstalls.create_time).filter(
                        UserSystemInfo.id == FailedInstalls.user_id,
                        FailedInstalls.name == failed_package['package_name'],
                        FailedInstalls.version == failed_package['version']
                    )

        else:
            if workshop_id:
                attempts = db.session.query(UserSystemInfo, Attempts).add_columns(
                    db.func.max(Attempts.id).label("attempt_id")).filter(
                    UserSystemInfo.unique_user_id == Attempts.unique_user_id,
                    UserSystemInfo.workshop_id == workshop_id
                ).group_by(Attempts.unique_user_id)

                latest_attempt_ids = [x.attempt_id for x in attempts]

                if not failed_package['version']:
                    user_info = db.session.query(FailedInstalls, UserSystemInfo.id).add_columns(
                        UserSystemInfo.distribution_name, UserSystemInfo.distribution_version,
                        UserSystemInfo.system, UserSystemInfo.system_platform,
                        UserSystemInfo.system_version, UserSystemInfo.machine,
                        UserSystemInfo.python_version, FailedInstalls.create_time).filter(
                        UserSystemInfo.id == FailedInstalls.user_id,
                        FailedInstalls.name == failed_package['package_name'],
                        FailedInstalls.attempt_id.in_(latest_attempt_ids),
                        UserSystemInfo.workshop_id == workshop_id
                    )
                else:
                    user_info = db.session.query(FailedInstalls, UserSystemInfo.id).add_columns(
                        UserSystemInfo.distribution_name, UserSystemInfo.distribution_version,
                        UserSystemInfo.system, UserSystemInfo.system_platform,
                        UserSystemInfo.system_version, UserSystemInfo.machine,
                        UserSystemInfo.python_version, FailedInstalls.create_time).filter(
                        UserSystemInfo.id == FailedInstalls.user_id,
                        FailedInstalls.name == failed_package['package_name'],
                        FailedInstalls.version == failed_package['version'],
                        FailedInstalls.attempt_id.in_(latest_attempt_ids),
                        UserSystemInfo.workshop_id == workshop_id
                    )

            else:

                attempts = db.session.query(db.func.max(Attempts.id)).group_by(Attempts.unique_user_id).all()
                latest_attempt_ids = [x[0] for x in attempts]
                if not failed_package['version']:
                    user_info = db.session.query(FailedInstalls, UserSystemInfo.id).add_columns(
                        UserSystemInfo.distribution_name, UserSystemInfo.distribution_version,
                        UserSystemInfo.system, UserSystemInfo.system_platform,
                        UserSystemInfo.system_version, UserSystemInfo.machine,
                        UserSystemInfo.python_version, FailedInstalls.create_time).filter(
                        UserSystemInfo.id == FailedInstalls.user_id,
                        FailedInstalls.name == failed_package['package_name'],
                        FailedInstalls.attempt_id.in_(latest_attempt_ids)
                    )
                else:
                    user_info = db.session.query(FailedInstalls, UserSystemInfo.id).add_columns(
                        UserSystemInfo.distribution_name, UserSystemInfo.distribution_version,
                        UserSystemInfo.system, UserSystemInfo.system_platform,
                        UserSystemInfo.system_version, UserSystemInfo.machine,
                        UserSystemInfo.python_version, FailedInstalls.create_time).filter(
                        UserSystemInfo.id == FailedInstalls.user_id,
                        FailedInstalls.name == failed_package['package_name'],
                        FailedInstalls.version == failed_package['version'],
                        FailedInstalls.attempt_id.in_(latest_attempt_ids)
                    )

        distribution_name = []
        distribution_version = []
        system = []
        system_platform = []
        system_version = []
        machine = []
        python_version = []
        distribution_name_version = []
        create_time = []
        for user in user_info:
            distribution_name.append(user.distribution_name)
            distribution_version.append(user.distribution_version)
            if user.distribution_version and user.distribution_name:
                distribution_name_version.append(user.distribution_name + " " + user.distribution_version)
            system.append(user.system)
            system_platform.append(user.system_platform)
            system_version.append(user.system_version)
            machine.append(user.machine)
            python_version.append(user.python_version)
            fail_date_time = user.create_time
            create_time.append(str(datetime.datetime.date(fail_date_time)))

        # Delete all None from the lists and count the frequency of each entity using Counter.
        # This create a dictionary with key as entity and count as its value.
        distribution_name = Counter(filter(None, distribution_name))
        distribution_version = Counter(filter(None, distribution_version))
        distribution_name_version = Counter(filter(None, distribution_name_version))
        system = Counter(filter(None, system))
        system_platform = Counter(filter(None, system_platform))
        system_version = Counter(filter(None, system_version))
        machine = Counter(filter(None, machine))
        python_version = Counter(filter(None, python_version))
        create_time = Counter(filter(None, create_time))

        #  Sort the dictionaries on counts of each key. This converts them to lists.
        python_version = sorted(python_version.items(), key=operator.itemgetter(1), reverse=True)
        system = sorted(system.items(), key=operator.itemgetter(1), reverse=True)
        distribution_name_version = sorted(distribution_name_version.items(), key=operator.itemgetter(1), reverse=True)
        system_platform = sorted(system_platform.items(), key=operator.itemgetter(1), reverse=True)
        system_version = sorted(system_version.items(), key=operator.itemgetter(1), reverse=True)
        machine = sorted(machine.items(), key=operator.itemgetter(1), reverse=True)
        if not failed_package['version']:
            failed_package['version'] = ""
        resp = {
            "package_name": failed_package['package_name'],
            "package_version": failed_package['version'],
            "user_system_info": {
                "distribution_name": distribution_name,
                "distribution_version": distribution_version,
                "distribution_name_version": distribution_name_version,
                "system": system,
                "system_version": system_version,
                "system_platform": system_platform,
                "machine": machine,
                "python_version": python_version
            },
            "create_time": create_time
        }
        package_details.append(resp)

    # if all attempts toggle is on, select all failed install for each attempt.
    if all_attempts:
        if workshop_id:
            failed_info = db.session.query(
                UserSystemInfo, FailedInstalls).add_columns(
                FailedInstalls.name, FailedInstalls.version, db.func.count().label("count")).filter(
                UserSystemInfo.id == FailedInstalls.user_id,
                UserSystemInfo.workshop_id == workshop_id).group_by(
                FailedInstalls.name, FailedInstalls.version)

            failed_info_names = db.session.query(
                UserSystemInfo, FailedInstalls).add_columns(
                FailedInstalls.name, db.func.count().label("count")).filter(
                UserSystemInfo.id == FailedInstalls.user_id,
                UserSystemInfo.workshop_id == workshop_id).group_by(FailedInstalls.name)
        else:
            failed_info = db.session.query(FailedInstalls.name, FailedInstalls.version,
                db.func.count().label("count")).group_by(FailedInstalls.name, FailedInstalls.version).all()

            failed_info_names = db.session.query(FailedInstalls.name,
                                                 db.func.count().label("count")).group_by(FailedInstalls.name).all()
    else:
        if workshop_id:
            attempts = db.session.query(
                UserSystemInfo, Attempts).add_columns(
                db.func.max(Attempts.id).label("attempt_id")).filter(
                UserSystemInfo.unique_user_id == Attempts.unique_user_id,
                UserSystemInfo.workshop_id == workshop_id
            ).group_by(Attempts.unique_user_id)
            latest_attempt_ids = [x.attempt_id for x in attempts]

            failed_info = db.session.query(
                FailedInstalls.name, FailedInstalls.version, db.func.count().label("count")).filter(
                FailedInstalls.attempt_id.in_(latest_attempt_ids)).group_by(
                FailedInstalls.name, FailedInstalls.version).all()

            failed_info_names = db.session.query(FailedInstalls.name, db.func.count().label("count")).filter(
                FailedInstalls.attempt_id.in_(latest_attempt_ids)).group_by(FailedInstalls.name).all()
        else:
            # select all the latest attempt_ids per unique user from attempts table
            attempts = db.session.query(db.func.max(Attempts.id)).group_by(Attempts.unique_user_id).all()
            latest_attempt_ids = [x[0] for x in attempts]

            # query failed_installs table with a filter : attempt_id in latest_attempt_ids.
            failed_info = db.session.query(
                FailedInstalls.name, FailedInstalls.version,
                db.func.count().label("count")).filter(
                FailedInstalls.attempt_id.in_(latest_attempt_ids)).group_by(
                FailedInstalls.name, FailedInstalls.version).all()

            failed_info_names = db.session.query(FailedInstalls.name, db.func.count().label("count")).filter(
                FailedInstalls.attempt_id.in_(latest_attempt_ids)).group_by(FailedInstalls.name).all()

    most_failed_packages = [
        {"name": fail.name, "version": fail.version, "count": fail.count}
        for fail in failed_info
    ]

    most_failed_package_names = [
        {"name": fail.name, "count": fail.count}
        for fail in failed_info_names
    ]

    most_failed_packages = sorted(most_failed_packages, key=lambda k: k['count'], reverse=True)
    most_failed_package_names = sorted(most_failed_package_names, key=lambda k: k['count'], reverse=True)

    # Get a list of all the workshops
    user_info = db.session.query(UserSystemInfo.workshop_id.distinct().label("workshop_id")).all()
    workshops = [
        user.workshop_id for user in user_info
        if user.workshop_id is not None
    ]

    response = {
        "package_details": package_details,
        "most_failed_packages": most_failed_packages,
        "most_failed_package_names": most_failed_package_names,
        "workshops": workshops,
        "workshop_id": workshop_id,
        "all_attempts": all_attempts
    }

    if request.args.get('export') == 'json':
        return make_response(json.dumps(response))

    return render_template('details.html', response=response)

@application.after_request
def inject_x_rate_headers(response):
    limit = get_view_rate_limit()
    if limit and limit.send_x_headers:
        h = response.headers
        h.add('X-RateLimit-Remaining', str(limit.remaining))
        h.add('X-RateLimit-Limit', str(limit.limit))
        h.add('X-RateLimit-Reset', str(limit.reset))
    return response


#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# vim:fenc=utf-8

"""
About: Forwarding VNF via packet socket.
"""

import argparse
import socket
import sys
import time

IFCE_NAME = "vnf-s1"
BUFFER_SIZE = 4096

def main():
    parser = argparse.ArgumentParser(description="Forwarding VNF")
    parser.add_argument(
        "--max", type=int, default=-1, help="Maximal number of forwarding frames"
    )
    args = parser.parse_args()

    buf = bytearray(BUFFER_SIZE)
    count = 0
    max_count = args.max
    print("*** Maximal forwarding number: {} (-1: infinite)".format(max_count))
    sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(3))
    sock.bind((IFCE_NAME, 0))
    print("*** Packet socket is bind, enter forwarding loop")
    try:
        while True:
            frame_len = sock.recv_into(buf, BUFFER_SIZE)
            count += 1
            if count == max_count:
                print("Reach maximal forwarding number, exits")
                sock.close()
                sys.exit(0)
            time.sleep(0.001)
            sock.send(buf[0:frame_len])
    except KeyboardInterrupt:
        sock.close()
        print("VNF exists.")
        sys.exit(0)

if __name__ == "__main__":
    main()


# -*- coding: utf-8 -*-
"""
Created on Wed May 13 16:20:22 2020

@author: jacesca@gmail.com
Chapter 3: Importing Data from Databases
    Combine pandas with the powers of SQL to find out just how many problems
    New Yorkers have with their housing. This chapter features introductory
    SQL topics like WHERE clauses, aggregate functions, and basic joins.
Source: https://learn.datacamp.com/courses/streamlined-data-ingestion-with-pandas
"""
###############################################################################
## Importing libraries
###############################################################################
# Load pandas and sqlalchemy's create_engine
import pandas as pd
import matplotlib.pyplot as plt

from sqlalchemy import create_engine

###############################################################################
## Preparing the environment
###############################################################################
# Global parameters
string_URL = 'sqlite:///NYC_weather.db'

# Create database engine to manage connections
engine = create_engine(string_URL)

# Global configuration
plt.rcParams.update({'axes.labelsize': 8, 'xtick.labelsize': 8, 'ytick.labelsize': 8,
                     'legend.fontsize': 6, 'font.size': 8})
suptitle_param = dict(color='darkblue', fontsize=9)
title_param    = {'color': 'darkred', 'fontsize': 10}

###############################################################################
## Main part of the code
###############################################################################
def Introduction_to_databases():
    print("****************************************************")
    topic = "1. Introduction to databases"; print("** %s" % topic)
    print("****************************************************")
    topic = "2. Connect to a database"; print("** %s" % topic)
    print("****************************************************")

    print('---------------------------------------------Exploring what is in the database')
    tables = engine.table_names()
    print(tables)

    print('---------------------------------------------Exploring tables')
    for table_data in tables:
        # Load entire table by table name
        df = pd.read_sql(table_data, engine)
        print(f"Head of {table_data}:\n{df.head()}")

    print('---------------------------------------------Using SQL sentences')
    # Load entire weather table with SQL
    weather = pd.read_sql("SELECT * FROM weather", engine)
    print(weather.head())

def Load_entire_tables():
    print("****************************************************")
    topic = "3. Load entire tables"; print("** %s" % topic)
    print("****************************************************")

    print('---------------------------------------------Reading hpd311calls')
    # Load hpd311calls without any SQL
    hpd_calls = pd.read_sql('hpd311calls', engine)
    # View the first few rows of data
    print(hpd_calls.head())

    print('---------------------------------------------Reading weather')
    # Create a SQL query to load the entire weather table
    query = """
    SELECT *
    FROM   weather;
    """
    # Load weather with the SQL query
    weather = pd.read_sql(query, engine)
    # View the first few rows of data
    print(weather.head())

def Refining_imports_with_SQL_queries():
    print("****************************************************")
    topic = "4. Refining imports with SQL queries"; print("** %s" % topic)
    print("****************************************************")

    print('---------------------------------------------SELECTing Columns')
    # Create a SQL query
    query = """
    SELECT date, tmax, tmin
    FROM   weather;
    """
    # Load weather with the SQL query
    df = pd.read_sql(query, engine)
    # View the first few rows of data
    print(df.head())

    print('---------------------------------------------Filtering by Numbers')
     # Create a SQL query
    query = """
    SELECT *
    FROM   weather
    WHERE  tmax > 32;
    """
    # Load weather with the SQL query
    df = pd.read_sql(query, engine)
    # View the first few rows of data
    print(df.head())

    print('---------------------------------------------Filtering Text')
     # Create a SQL query
    query = """
    /* Get records about incidents in Brooklyn */
    SELECT *
    FROM   hpd311calls
    WHERE  borough = 'BROOKLYN';
    """
    # Load weather with the SQL query
    df = pd.read_sql(query, engine)
    # View the first few rows of data
    print(df.head())
    print("Distinct values in borough column: ", df.borough.unique())

    print('---------------------------------------------Combining Conditions: AND')
     # Create a SQL query
    query = """SELECT *
               FROM   hpd311calls
               WHERE  borough = 'BRONX'
                      AND complaint_type = 'PLUMBING';"""
    # Load weather with the SQL query
    df = pd.read_sql(query, engine)
    # Check record count
    print("Shape: ", df.shape)

    print('---------------------------------------------Combining Conditions: OR')
     # Create a SQL query
    query = """SELECT *
               FROM   hpd311calls
               WHERE  complaint_type = 'WATER LEAK'
                      OR complaint_type = 'PLUMBING';"""
    # Load weather with the SQL query
    df = pd.read_sql(query, engine)
    # Check record count
    print("Shape: ", df.shape)

def Selecting_columns_with_SQL():
    print("****************************************************")
    topic = "5. Selecting columns with SQL"; print("** %s" % topic)
    print("****************************************************")

    print('---------------------------------------------Passing a query')
    # Write query to get date, tmax, and tmin from weather
    query = """
    SELECT date,
           tmax,
           tmin
    FROM   weather;
    """
    # Make a data frame by passing query and engine to read_sql()
    temperatures = pd.read_sql(query, engine)
    # View the resulting data frame
    print(temperatures)

def Selecting_rows():
    print("****************************************************")
    topic = "6. Selecting rows"; print("** %s" % topic)
    print("****************************************************")

    print('---------------------------------------------Extracting the data')
    # Create query to get hpd311calls records about safety
    query = """
    SELECT *
    FROM   hpd311calls
    WHERE  complaint_type='SAFETY';
    """
    # Query the database and assign result to safety_calls
    safety_calls = pd.read_sql(query, engine)

    print('---------------------------------------------Summarizing the data')
    call_counts = safety_calls.groupby('borough').unique_key.count()
    print(call_counts)

    print('---------------------------------------------Plotting the information')
    # Graph the number of safety calls by borough
    fig, ax = plt.subplots()
    call_counts.plot.barh(ax=ax)
    ax.set_xlabel('Frequency')
    ax.set_title('Complaints by City', **title_param)
    fig.suptitle(topic, **suptitle_param)
    plt.subplots_adjust(left=.2, bottom=None, right=.95, top=None, wspace=None, hspace=None); #To set the margins
    plt.show()

def Filtering_on_multiple_conditions():
    print("****************************************************")
    topic = "7. Filtering on multiple conditions"; print("** %s" % topic)
    print("****************************************************")

    print('---------------------------------------------Selecting base on conditions')
    # Create query for records with max temps <= 32 or snow >= 1
    query = """
    SELECT *
    FROM   weather
    WHERE  tmax<=32
           OR snow>=1;
    """
    # Query database and assign result to wintry_days
    wintry_days = pd.read_sql(query, engine)
    # View summary stats about the temperatures
    print(wintry_days.describe())

def More_complex_SQL_queries():
    print("****************************************************")
    topic = "8. More complex SQL queries"; print("** %s" % topic)
    print("****************************************************")

    print('---------------------------------------------GROUP BY clause')
    # Write query to get plumbing call counts by borough
    query = """SELECT   borough, COUNT(*)
               FROM     hpd311calls
               WHERE    complaint_type = 'PLUMBING'
               GROUP BY borough;"""
    # Query databse and create data frame
    plumbing_call_counts = pd.read_sql(query, engine)
    print(plumbing_call_counts)

def Getting_distinct_values():
    print("****************************************************")
    topic = "9. Getting distinct values"; print("** %s" % topic)
    print("****************************************************")

    print('---------------------------------------------DISTINCT clause')
    # Create query for unique combinations of borough and complaint_type
    query = """
    SELECT DISTINCT borough,
           complaint_type
    FROM   hpd311calls;
    """
    # Load results of query to a data frame
    issues_and_boros = pd.read_sql(query, engine)
    # Check assumption about issues and boroughs
    print(issues_and_boros)

def Counting_in_groups():
    print("****************************************************")
    topic = "10. Counting in groups"; print("** %s" % topic)
    print("****************************************************")

    print('---------------------------------------------Extracting and summarizing the data')
    # Create query to get call counts by complaint_type
    query = """
    SELECT   complaint_type,
             COUNT(*) as issues_counts
    FROM     hpd311calls
    GROUP BY complaint_type;
    """
    # Create data frame of call counts by issue
    calls_by_issue = pd.read_sql(query, engine)

    print('---------------------------------------------Plotting the information')
    # Graph the number of calls for each housing issue
    fig, ax = plt.subplots()
    calls_by_issue.plot.barh(x="complaint_type", ax=ax)
    ax.set_xlabel('Frequency')
    ax.set_title('Complaints by Issue', **title_param)
    fig.suptitle(topic, **suptitle_param)
    plt.subplots_adjust(left=.3, bottom=None, right=.95, top=None, wspace=None, hspace=None); #To set the margins
    plt.show()

def Working_with_aggregate_functions():
    print("****************************************************")
    topic = "11. Working with aggregate functions"; print("** %s" % topic)
    print("****************************************************")

    print('---------------------------------------------GROUP BY clause')
    # Create query to get temperature and precipitation by month
    query = """
    SELECT   month,
             MAX(tmax), MIN(tmin), SUM(prcp)
    FROM     weather
    GROUP BY month;
    """
    # Get data frame of monthly weather stats
    weather_by_month = pd.read_sql(query, engine)
    # View weather stats by month
    print(weather_by_month)

def Loading_multiple_tables_with_joins():
    print("****************************************************")
    topic = "12. Loading multiple tables with joins"; print("** %s" % topic)
    print("****************************************************")

    print('---------------------------------------------Joining Tables')
    query = """
    SELECT *
    FROM   hpd311calls
    JOIN   weather
           ON hpd311calls.created_date = weather.date;
    """
    # Get data frame of monthly weather stats
    df = pd.read_sql(query, engine)
    # View shape of the data
    print('shape: ', df.shape)

    print('---------------------------------------------Joining and Filtering')
    query = """
    /* Get only heat/hot water calls and join in weather data */
    SELECT *
    FROM   hpd311calls
    JOIN   weather
           ON hpd311calls.created_date = weather.date
    WHERE  hpd311calls.complaint_type = 'HEAT/HOT WATER';
    """
    # Get data frame of monthly weather stats
    df = pd.read_sql(query, engine)
    # View shape of the data
    print('shape: ', df.shape)

    print('---------------------------------------------(1) Joining and Aggregating')
    query = """
    /* Get call counts by borough */
    SELECT   hpd311calls.borough, COUNT(*)
    FROM     hpd311calls
    GROUP BY hpd311calls.borough;
    """
    # Get data frame of monthly weather stats
    df = pd.read_sql(query, engine)
    # View shape of the data
    print(df)

    print('---------------------------------------------(2) Joining and Aggregating')
    query = """
    /* Get call counts by borough and join in population and housing counts */
    SELECT   hpd311calls.borough,
             COUNT(*),
             boro_census.total_population, boro_census.housing_units
    FROM     hpd311calls
    JOIN     boro_census
             ON hpd311calls.borough = boro_census.borough
    GROUP BY hpd311calls.borough
    """
    # Get data frame of monthly weather stats
    df = pd.read_sql(query, engine)
    # View shape of the data
    print(df)

def Joining_tables():
    print("****************************************************")
    topic = "13. Joining tables"; print("** %s" % topic)
    print("****************************************************")

    print('---------------------------------------------JOIN clause')
    # Query to join weather to call records by date columns
    query = """
    SELECT *
    FROM   hpd311calls
    JOIN   weather
           ON hpd311calls.created_date = weather.date;
    """
    # Create data frame of joined tables
    calls_with_weather = pd.read_sql(query, engine)
    # View the data frame to make sure all columns were joined
    print(calls_with_weather.head())

def Joining_and_filtering():
    print("****************************************************")
    topic = "14. Joining and filtering"; print("** %s" % topic)
    print("****************************************************")

    print('---------------------------------------------Joining')
    # Query to get hpd311calls and precipitation values
    query = """
    SELECT hpd311calls.*,
           weather.prcp
       FROM hpd311calls
      JOIN weather
      ON hpd311calls.created_date = weather.date;"""
    # Load query results into the leak_calls data frame
    leak_calls = pd.read_sql(query, engine)
    # View the data frame
    print(leak_calls.head())

    print('---------------------------------------------Filtering')
    # Query to get water leak calls and daily precipitation
    query = """
    SELECT  hpd311calls.*, weather.prcp
    FROM    hpd311calls
    JOIN    weather
            ON hpd311calls.created_date = weather.date
    WHERE   hpd311calls.complaint_type = 'WATER LEAK';"""
    # Load query results into the leak_calls data frame
    leak_calls = pd.read_sql(query, engine)
    # View the data frame
    print(leak_calls.head())

def Joining_filtering_and_aggregating():
    print("****************************************************")
    topic = "15. Joining, filtering, and aggregating"; print("** %s" % topic)
    print("****************************************************")

    print('---------------------------------------------GROUP BY clause')
    # Query to get heat/hot water call counts by created_date
    query = """
    SELECT   hpd311calls.created_date,
             COUNT(*)
    FROM     hpd311calls
    WHERE    hpd311calls.complaint_type = 'HEAT/HOT WATER'
    GROUP BY hpd311calls.created_date;
    """
    # Query database and save results as df
    df = pd.read_sql(query, engine)
    # View first 5 records
    print(df.head())

    print('---------------------------------------------JOIN clause')
    # Modify query to join tmax and tmin from weather by date
    query = """
    SELECT   hpd311calls.created_date,
             COUNT(*),
             weather.tmax, weather.tmin
    FROM     hpd311calls
    JOIN     weather
             ON hpd311calls.created_date = weather.date
    WHERE    hpd311calls.complaint_type = 'HEAT/HOT WATER'
    GROUP BY hpd311calls.created_date;
    """
    # Query database and save results as df
    df = pd.read_sql(query, engine)
    # View first 5 records
    print(df.head())

def main():
    print("\n\n****************************************************")
    print("** BEGIN                                          **")

    Introduction_to_databases()
    Load_entire_tables()
    Refining_imports_with_SQL_queries()
    Selecting_columns_with_SQL()
    Selecting_rows()
    Filtering_on_multiple_conditions()
    More_complex_SQL_queries()
    Getting_distinct_values()
    Counting_in_groups()
    Working_with_aggregate_functions()
    Loading_multiple_tables_with_joins()
    Joining_tables()
    Joining_and_filtering()
    Joining_filtering_and_aggregating()

    print("\n\n****************************************************")
    print("** END                                            **")
    print("****************************************************")

if __name__ == '__main__':
    main()

Streamlined Data Ingestion with pandas/03_Importing_Data_from_Databases.py


from src.forecaster.base_forecaster import BaseForecaster
from statsmodels.tsa.statespace.varmax import VARMAX
from src.utils.data_utils import EPS
import numpy as np
import pandas as pd
import os
import pickle

class VARMAForecaster(BaseForecaster):

    def __init__(self, name, preprocess, market_train, market_test):
        super().__init__(name, preprocess, market_train)

        # from previous tests: only high prices granger-cause close prices
        self.data = self._process_data(market_test)

    def _forecast(self, step):
        obj_cols = [f'{stock}_close' for stock in self.market_train.stock_names[1:]]
        return self.model.predict(step, step)[obj_cols].values[0]

    def fit_test_model_given_par(self, p, q, render=False, maxiter=50):
        # fit model on train data, test both in and out of sample and plot results
        # equivalent to forecast_all method of nn_forecaster
        data_train = self.data[:self.id_sep]
        data_test = self.data[self.id_sep:]

        self.model = self._fit_model(data_train, p, q, maxiter=maxiter)

        obj_cols = [f'{stock}_close' for stock in self.market_train.stock_names[1:]]

        pred_vec_train = self.model.predict()[obj_cols].values
        truth_vec_train = data_train[obj_cols].values
        rmse_train = self._calculate_rmse(pred_vec_train, truth_vec_train)

        rmse_test, pred_vec_test, truth_vec_test, self.model = self._eval(self.model, data_test)

        if render:
            self.plot_all(pred_vec_train, truth_vec_train, pred_vec_test, truth_vec_test)

        return rmse_train, rmse_test

    def train(self, save_path, maxiter=50, maxlag=5, numfolds=5):
        import warnings
        warnings.filterwarnings("ignore")

        print('Start train')

        # creating directory to store models if it doesn't exist
        if not os.path.isdir(save_path):
            os.makedirs(save_path)

        rmse_results = np.zeros((maxlag, maxlag, numfolds))

        # create train-val-test splits for cross-validation
        data_train = self.data[:self.id_sep]
        k, m = divmod(data_train.shape[0], numfolds)
        splits = [(i+1)*k+min(i+1, m) for i in range(numfolds)]

        for fold in range(3,numfolds-1):
            split_train = data_train[0:splits[fold]]
            split_test = data_train[splits[fold]:splits[fold+1]]

            for p in range(maxlag):
                for q in range(maxlag):
                    if p + q > 0:
                        print(f'Currently: fold = {fold}, p = {p}, q = {q}', end=' - ')
                        model = self._fit_model(split_train, p, q, maxiter=maxiter)
                        print('Start val', end=' - ')
                        rmse, _, _, _ = self._eval(model, split_test)
                        rmse_results[p,q,fold] = rmse
                        print(f'Loss = {rmse:.6f}')

        rmse_mean = rmse_results.mean(axis=-1)

        best_idx = rmse_mean.argmax()
        best_p = best_idx // maxlag
        best_q = best_idx % maxlag

        print(f'Best model found: p = {best_p}, q = {best_q}')
        rmse_train, rmse_test = self.fit_test_model_given_par(best_p, best_q, render=True, maxiter=maxiter)
        print(f'Train loss = {rmse_train} - Test loss = {rmse_test}')

        # save model
        with open(f'{save_path}/varma_p{best_p}_q{best_q}.pkl', 'wb') as outp:
            pickle.dump(self.__dict__, outp, pickle.HIGHEST_PROTOCOL)

        return rmse_train, rmse_test, (best_p, best_q)

    def load_model(self, model_path):
        self.__dict__.clear()
        with open(model_path, 'rb') as inp:
            self.__dict__.update(pickle.load(inp))

    def _fit_model(self, data, p, q, maxiter=50):
        model = VARMAX(data, order=(p,q))
        model_fit = model.fit(maxiter=maxiter, disp=False)
        return model_fit

    def _eval(self, model, data):
        # assuming eval data directly follows train data
        model_new = model
        obj_cols = [f'{stock}_close' for stock in self.market_train.stock_names[1:]]

        # rolling window setup for out of sample forecasting
        num_obs = data.shape[0]
        model_new = model_new.append(data)
        pred_vec = model_new.predict(-num_obs)
        truth_vec = data[obj_cols].values
        pred_vec = pred_vec[obj_cols].values

        rmse = self._calculate_rmse(pred_vec, truth_vec)
        return rmse, pred_vec, truth_vec, model_new

    def _process_data(self, market_test):

        data_train = self.market_train.data
        data_test = market_test.data
        data = np.concatenate((data_train, data_test), axis=1)

        #dates_train = self.market_train.date_list
        #dates_test = market_test.date_list
        #date_list = dates_train + dates_test

        self.id_sep = data_train.shape[1] - 1
        # id of start of testing data

        data = data[1:,:,[1,3]] # take only high and close
        data = np.transpose(data, [1,0,2]) # shape = [window_length, stocks, features]
        data = np.reshape(data, [data.shape[0], data.shape[1] * data.shape[2]])

        if self.preprocess == 'log_return':
            new = data[1:,:]
            old = data[:-1,:]
            data = np.log(new + EPS) - np.log(old + EPS)

        stock_names = self.market_train.stock_names[1:]
        features_used = ['high','close']
        all_features = [f'{stock}_{feature}' for stock in stock_names for feature in features_used]

        data = pd.DataFrame(data, columns=all_features)
        #data['dates'] = pd.to_datetime(date_list[1:])
        #data.set_index('dates', inplace=True)

        return data


head = [1,2,3,4,5]

# Definition for singly-linked list.
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

# curr = head
# prev = None

# 1. get next list node (at start, 2->3->4->5), assign to var next
# 2. assign curr's next list node to prev, thereby always adding the last value to curr.next
# 3. add curr(final node(s)) to prev first, and the first one added will be the last node (1)
# 4. "iterate" by assigning next to curr, thereby removing previous node

# while curr:
#     next = curr.next # 1
#     curr.next = prev # 2
#     prev = curr # 3
#     curr = next # 4

class Solution:
    def reverseList(self, head):
        i = 0
        rev_list = ListNode()

        while i < len(head):
            next = i + 1 if i < len(head)-1 else 0
            rev_list.val = head[i]
            rev_list.next = head[next]
            i += 1
        return rev_list

s = Solution()
print(s.reverseList(head).val)


#Need to download simpleguitk to run this script
import simpleguitk as simplegui

# define global variables

enter_time = 0
enter_break = 0
training_minutes = 0
resting_seconds = 0
interval_num = 0
initial_training_minutes = 0
initial_resting_seconds = 0

# define helper function format that converts time
# in tenths of seconds into formatted string A:BC.D

def workout_watch(training_minutes):
    '''This helper function converts minutes into
    a stop watch format '''
    minute = 0
    tenths_second = training_minutes % 10
    second = (training_minutes - tenths_second) % 100/10
    subtractor = (training_minutes - tenths_second) % 100
    ten_second = (training_minutes -(tenths_second + subtractor))/100

    if ten_second > 5:
        minute = ten_second/6
        ten_second = ten_second % 6

    return str(int(minute)) + ":" + str(int(ten_second)) + str(int(second)) + "." + str(int(tenths_second))

def resting_watch(resting_seconds):
    '''This helper function converts seconds into
    a stop watch format '''
    minute = 0
    tenths_second = resting_seconds % 10
    second = (resting_seconds - tenths_second) % 100/10
    subtractor = (resting_seconds - tenths_second) % 100
    ten_second = (resting_seconds -(tenths_second + subtractor))/100

    if ten_second > 5:
        minute = ten_second/6
        ten_second = ten_second % 6

    return str(int(minute)) + ":" + str(int(ten_second)) + str(int(second)) + "." + str(int(tenths_second))

def interval(interval_num):
    '''This helper function converts your interval in int into a string
    so it could be read by our event handler '''
    string = interval_num
    return str(int(string))

# define event handlers for buttons; "Start", "Stop", "Reset"

def start():
    '''This event handler starts the stop watches'''
    global timer_running
    timer.start()

def stop ():
    '''This event handler stops the stop watches'''
    timer.stop ()

def reset ():
    '''This event handler resets the stop watches'''
    global training_minutes,resting_seconds,interval_num
    timer.stop()
    training_minutes = 0
    resting_seconds = 0
    interval_num = 0

# define event handler for timer with 0.1 sec interval

def timer_handler():
    '''This time handler play alarms, reduces intervals and restarts the clock'''
    global training_minutes, resting_seconds, interval_num, initial_training_minutes, initial_resting_seconds
    if interval_num > 0:
            if training_minutes != 0:
                training_minutes -= 1
                if training_minutes == 0:
                    rest.play()
            elif resting_seconds != 0:
                resting_seconds -= 1
                if resting_seconds == 0:
                    go.play()
            else:
                training_minutes = initial_training_minutes
                resting_seconds = initial_resting_seconds
                interval_num -= 1

def train_input_handler(text):
    '''Adds training time in minutes'''
    global enter_time, training_minutes, initial_training_minutes
    enter_time = int(text)
    training_minutes = enter_time * 600
    initial_training_minutes = training_minutes

def rest_input_handler(text):
    '''Adds resting time in seconds'''
    global enter_break, resting_seconds, initial_resting_seconds
    enter_break = int(text)
    resting_seconds = enter_break * 10
    initial_resting_seconds = resting_seconds

def intervals_input_handler(text):
    '''Adds intervals'''
    global interval_num
    interval_num = int(text)

# define draw handler

def draw_handler(canvas):
    '''This draw handlers draw the training stop watch, the resting
    stop watch and the interval number'''
    canvas.draw_text(workout_watch(training_minutes),[110,180], 60, "White")
    canvas.draw_text(resting_watch(resting_seconds),[110,330], 60, "Yellow")
    canvas.draw_text(interval(interval_num),[345,60], 40, "Green")

# create frame

frame = simplegui.create_frame('Stop Watch: The Game', 400, 400)

# create sound variables

go = simplegui.load_sound('https://www.dropbox.com/s/qwj153wzm7derup/lets_go.ogg?dl=1')
rest = simplegui.load_sound('https://www.dropbox.com/s/m921ljc4whji8pc/rest.ogg?dl=1')

# register event handlers

timer = simplegui.create_timer(100, timer_handler)
frame.set_draw_handler(draw_handler)

#frame.set_draw_handler()

frame.add_button("Start", start, 80)
frame.add_button("Stop", stop, 80)
frame.add_button("Reset", reset, 80)
frame.add_input('Excercise, Enter Minutes',train_input_handler,140)
frame.add_input('Rest, Enter Seconds',rest_input_handler,140)
frame.add_input('intervals',intervals_input_handler,140)

# start frame

frame.start()


import paddle
from typing import Optional
from .ops import spline_weighting, spline_basis

def scatter_max(inputs, idx, val):
    idx_expanded = idx.unsqueeze(-1).expand_as(val)
    cidx = paddle.cast(idx.unsqueeze(-1), val.dtype)
    twosort = paddle.argsort(cidx * (val.max() - val.min() + 2) + val, axis=0)
    gaidx = paddle.stack([
        twosort, paddle.arange(twosort.shape[-1]).unsqueeze(0).expand_as(twosort)
    ], axis=-1)
    gidx = paddle.gather_nd(idx_expanded, gaidx)
    mask = paddle.cast(
        gidx != paddle.concat([gidx[1:], paddle.full_like(gidx[:1], -1)]), 'int64'
    )
    return inputs.scatter(
        paddle.sort(idx),
        paddle.gather_nd(val, gaidx) * mask, overwrite=False
    )

def spline_conv(x: paddle.Tensor, edge_index: paddle.Tensor,
                pseudo: paddle.Tensor, weight: paddle.Tensor,
                kernel_size: paddle.Tensor, is_open_spline: paddle.Tensor,
                degree: int = 1, aggr: str = 'mean',
                root_weight: Optional[paddle.Tensor] = None,
                bias: Optional[paddle.Tensor] = None) -> paddle.Tensor:
    r"""Applies the spline-based convolution operator :math:`(f \star g)(i) =
    \frac{1}{|\mathcal{N}(i)|} \sum_{l=1}^{M_{in}} \sum_{j \in \mathcal{N}(i)}
    f_l(j) \cdot g_l(u(i, j))` over several node features of an input graph.
    The kernel function :math:`g_l` is defined over the weighted B-spline
    tensor product basis for a single input feature map :math:`l`.

    x: (number_of_nodes, in_channels), input node features.
    edge_index: (2, number_of_edges)-int, graph edges, given by source and
        target indices, of shape (2 x number_of_edges) in the fixed
        interval [0, 1]
    pseudo: (number_of_edges, dim),
        edge attributes, ie. pseudo coordinates in the fixed interval [0, 1]
    weight: (kernel_size ** dim, in_channels, out_channels),
        trainable weight parameters
    kernel_size: int, number of trainable weight parameters in each edge dimension
    is_open_spline: (dim)-int, {0, 1}, whether to use open or closed B-spline bases
        for each edge dimension
    degree: int, B-spline basis degree (only 1 the default is supported by now)
    aggr: 'mean', 'max' or 'sum', aggregation function of output (default: mean)
    root_weight: (in_channels, out_channels), additional shared trainable
        parameters for each feature of the root node of shape (default: None)
    bias: (out_channels), Optional bias of shape (default: None)
    """
    assert aggr in ['sum', 'mean', 'max'], "Unsupported aggregation"
    x = x.unsqueeze(-1) if x.dim() == 1 else x
    pseudo = pseudo.unsqueeze(-1) if pseudo.dim() == 1 else pseudo

    row, col = edge_index[0], edge_index[1]
    N, E, M_out = x.shape[0], row.shape[0], weight.shape[2]

    # Weight each node.
    basis, weight_index = spline_basis(pseudo, kernel_size, is_open_spline, degree)

    out = spline_weighting(paddle.gather(x, col, axis=0), weight, basis, weight_index)

    # Convert E x M_out to N x M_out features.
    # row_expanded = row.unsqueeze(-1).expand_as(out).reshape([-1])
    if aggr in ['sum', 'mean']:
        out = paddle.zeros(
            (N, M_out), dtype=out.dtype
        ).scatter(row.reshape([-1]), out, overwrite=False)
    if aggr == 'max':
        out = scatter_max(paddle.zeros(
            (N, M_out), dtype=out.dtype
        ), row, out)

    # Normalize out by node degree (if wished).
    if aggr == 'mean':
        ones = paddle.ones((E,), dtype=x.dtype)
        deg = paddle.zeros(
            (N,), dtype=x.dtype
        ).scatter(row.reshape([-1]), ones.reshape([-1]), overwrite=False)
        out = out / paddle.clip(deg.unsqueeze(-1), min=1)

    # Weight root node separately (if wished).
    if root_weight is not None:
        out = out + paddle.matmul(x, root_weight)

    # Add bias (if wished).
    if bias is not None:
        out = out + bias

    return out


import pandas as pd
from tqdm import tqdm
from model.QACGBERT import *
from util.tokenization import *
from torch.utils.data import DataLoader, TensorDataset
import random
import warnings

warnings.filterwarnings('ignore')

context_id_map_fiqa = {'stock': 0,
                       'corporate': 1,
                       'market': 2,
                       'economy': 3}

class InputExample(object):
    def __init__(self, guid, text_a, text_b=None, label=None):
        self.guid = guid
        self.text_a = text_a
        self.text_b = text_b
        self.label = label

class InputFeatures(object):
    def __init__(self, input_ids, input_mask, segment_ids, score, seq_len, context_ids):
        self.input_ids = input_ids
        self.input_mask = input_mask
        self.segment_ids = segment_ids
        self.score = score
        self.seq_len = seq_len
        self.context_ids = context_ids

def convert_to_unicode(text):
    if six.PY3:
        if isinstance(text, str):
            return text
        elif isinstance(text, bytes):
            return text.decode("utf-8", "ignore")
        else:
            raise ValueError("Unsupported string type: %s" % (type(text)))
    else:
        raise ValueError("Not running on Python 3")

def get_test_examples(path):
    test_data = pd.read_csv(path, header=None).values
    def _create_examples(lines, set_type):
        examples = []
        for (i, line) in enumerate(lines):
            guid = "%s-%s" % (set_type, i)
            text_a = convert_to_unicode(str(line[0]))
            text_b = convert_to_unicode(str(line[1]))
            label = float(0)
            examples.append(
                InputExample(guid=guid, text_a=text_a, text_b=text_b, label=label))
        return examples
    return _create_examples(test_data, "test")

def truncate_seq_pair(tokens_a, tokens_b, max_length):
    while True:
        total_length = len(tokens_a) + len(tokens_b)
        if total_length <= max_length:
            break
        if len(tokens_a) > len(tokens_b):
            tokens_a.pop()
        else:
            tokens_b.pop()

def convert_examples_to_features(examples, max_seq_length,
                                 tokenizer, max_context_length,
                                 context_standalone, args):
    features = []
    for (ex_index, example) in enumerate(tqdm(examples)):
        tokens_a = tokenizer.tokenize(example.text_a)

        tokens_b = None
        if example.text_b:
            tokens_b = tokenizer.tokenize(example.text_b)
        tokens_context = None
        if example.text_b:
            tokens_context = tokenizer.tokenize(example.text_b)

        if tokens_b and not context_standalone:
            truncate_seq_pair(tokens_a, tokens_b, max_seq_length - 3)
        else:
            if len(tokens_a) > max_seq_length - 2:
                tokens_a = tokens_a[0:(max_seq_length - 2)]

        tokens = []
        segment_ids = []
        tokens.append("[CLS]")
        segment_ids.append(0)
        for token in tokens_a:
            tokens.append(token)
            segment_ids.append(0)
        tokens.append("[SEP]")
        segment_ids.append(0)

        if tokens_b and not context_standalone:
            for token in tokens_b:
                tokens.append(token)
                segment_ids.append(1)
            tokens.append("[SEP]")
            segment_ids.append(1)

        input_ids = tokenizer.convert_tokens_to_ids(tokens)

        context_ids = []
        if tokens_context:
            context_ids = [context_id_map_fiqa[example.text_b]]

        # The mask has 1 for real tokens and 0 for padding tokens. Only real
        # tokens are attended to.
        input_mask = [1] * len(input_ids)

        # Zero-pad up to the sequence length.
        seq_len = len(input_ids)
        while len(input_ids) < max_seq_length:
            input_ids.append(0)
            input_mask.append(0)
            segment_ids.append(0)

        while len(context_ids) < max_context_length:
            context_ids.append(0)

        assert len(input_ids) == max_seq_length
        assert len(input_mask) == max_seq_length
        assert len(segment_ids) == max_seq_length
        assert len(context_ids) == max_context_length

        features.append(
            InputFeatures(
                input_ids=input_ids,
                input_mask=input_mask,
                segment_ids=segment_ids,
                score=example.label,
                seq_len=seq_len,
                context_ids=context_ids))

    return features

def get_model_and_tokenizer(vocab_file,
                               bert_config_file=None, init_checkpoint=None,
                               do_lower_case=True,
                               init_lrp=False):
    tokenizer = FullTokenizer(
        vocab_file=vocab_file, do_lower_case=do_lower_case, pretrain=False)
    if bert_config_file is not None:
        bert_config = BertConfig.from_json_file(bert_config_file)
    else:
        bert_config = BertConfig(
            hidden_size=768,
            num_hidden_layers=12,
            num_attention_heads=12,
            intermediate_size=3072,
            hidden_act="gelu",
            hidden_dropout_prob=0.1,
            attention_probs_dropout_prob=0.1,
            max_position_embeddings=512,
            type_vocab_size=2,
            initializer_range=0.02
        )
    bert_config.vocab_size = len(tokenizer.vocab)
    model = QACGBertForSequenceScore(
                bert_config,
                init_weight=True,
                init_lrp=init_lrp)

    if init_checkpoint is not None:
        if "checkpoint" in init_checkpoint:
            state_dict = torch.load(init_checkpoint, map_location='cpu')
            from collections import OrderedDict
            new_state_dict = OrderedDict()
            for k, v in state_dict.items():
                if k.startswith('module.'):
                    name = k[7:]
                    new_state_dict[name] = v
                else:
                    new_state_dict[k] = v
            model.load_state_dict(new_state_dict)
        else:
            model.bert.load_state_dict(torch.load(init_checkpoint, map_location='cpu'), strict=False)
    return model, tokenizer

def system_setups(args):
    # system related setups
    if args.local_rank == -1 or args.no_cuda:
        device = torch.device("cuda" if torch.cuda.is_available() and not args.no_cuda else "cpu")
        n_gpu = torch.cuda.device_count()
    else:
        device = torch.device("cuda", args.local_rank)
        n_gpu = 1
        torch.distributed.init_process_group(backend='nccl')

    random.seed(args.seed)
    np.random.seed(args.seed)
    torch.manual_seed(args.seed)
    if n_gpu > 0:
        torch.cuda.manual_seed_all(args.seed)

    if args.bert_config_file is not None:
        bert_config = BertConfig.from_json_file(args.bert_config_file)
        if args.max_seq_length > bert_config.max_position_embeddings:
            raise ValueError(
                "Cannot use sequence length {} because the BERT model was only trained up to sequence length {}".format(
                args.max_seq_length, bert_config.max_position_embeddings))

    return device, n_gpu

def data_and_model_loader(device, n_gpu, args):
    model, tokenizer = get_model_and_tokenizer(vocab_file=args.vocab_file,
                                bert_config_file=args.bert_config_file, init_checkpoint=args.init_checkpoint,
                                do_lower_case=True,
                                init_lrp=False)

    test_examples = get_test_examples(args.path)
    test_features = convert_examples_to_features(
        test_examples, args.max_seq_length,
        tokenizer, args.max_context_length,
        args.context_standalone, args)

    all_input_ids = torch.tensor([f.input_ids for f in test_features], dtype=torch.long)
    all_input_mask = torch.tensor([f.input_mask for f in test_features], dtype=torch.long)
    all_segment_ids = torch.tensor([f.segment_ids for f in test_features], dtype=torch.long)
    all_score = torch.tensor([f.score for f in test_features], dtype=torch.float)
    all_seq_len = torch.tensor([[f.seq_len] for f in test_features], dtype=torch.long)
    all_context_ids = torch.tensor([f.context_ids for f in test_features], dtype=torch.long)

    test_data = TensorDataset(all_input_ids, all_input_mask, all_segment_ids,
                              all_score, all_seq_len, all_context_ids)
    test_dataloader = DataLoader(test_data, shuffle=False)

    if args.local_rank != -1:
        model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.local_rank],
                                                          output_device=args.local_rank)
    elif n_gpu > 1:
        model = torch.nn.DataParallel(model)
    model.to(device)

    return model, test_dataloader

def pred(args):
    device, n_gpu = system_setups(args)
    model, test_dataloader = data_and_model_loader(device, n_gpu, args)

    model.eval()
    y_pred = []
    for batch in list(test_dataloader):
        if torch.cuda.is_available():
            torch.cuda.empty_cache()
        input_ids, input_mask, segment_ids, score, seq_lens, \
            context_ids = batch
        max_seq_lens = max(seq_lens)[0]
        input_ids = input_ids[:, :max_seq_lens]
        input_mask = input_mask[:, :max_seq_lens]
        segment_ids = segment_ids[:, :max_seq_lens]

        input_ids = input_ids.to(device)
        input_mask = input_mask.to(device)
        segment_ids = segment_ids.to(device)
        score = score.to(device)
        seq_lens = seq_lens.to(device)
        context_ids = context_ids.to(device)

        _, pred_score, _, _, _, _ = \
            model(input_ids, segment_ids, input_mask, seq_lens, device=device, labels=score,
                  context_ids=context_ids)
        y_pred.append(pred_score.detach().numpy()[0][0])

    return y_pred

if __name__ == '__main__':
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("--path")
    parser.add_argument("--max_seq_length", default=128, type=int)
    parser.add_argument("--vocab_file")
    parser.add_argument("--bert_config_file")
    parser.add_argument("--init_checkpoint")
    parser.add_argument('--local_rank', type=int, default=-1)
    parser.add_argument("--no_cuda", default=False, action='store_true')
    parser.add_argument("--max_context_length", default=1, type=int)
    parser.add_argument("--context_standalone", default=False, action='store_true')
    parser.add_argument('--seed', type=int, default=123)
    args = parser.parse_args()

    pred_score = pred(args)
    test_data = pd.read_csv(args.path, header=None)
    test_data['score'] = pred_score
    test_data.to_csv('absa_out.csv', index=None, header=None)
    print(test_data)


from django.urls import path
from . import views
from .views import home, catalog, product_detail, cart, delivery, about, profile, add_to_cart, \
    remove_from_cart
from .views import contact, add_product, registration, user_login, user_logout, order_create, order_detail

app_name = 'myapp'

urlpatterns = [
    path('', home, name='home'),
    path('catalog/', catalog, name='catalog'),
    path('product/<int:product_id>/', product_detail, name='product_detail'),
    path('cart/', cart, name='cart'),
    path('delivery/', delivery, name='delivery'),
    path('about/', about, name='about'),
    path('contact/', contact, name='contact'),
    path('add-product/', add_product, name='add_product'),
    path('registration/', registration, name='registration'),
    path('user_login/', user_login, name='user_login'),
    path('logout/', user_logout, name='logout'),
    path('profile/', profile, name='profile'),
    path('catalog/product/<int:product_id>/', product_detail, name='product_detail'),
    path('order_create/', views.order_create, name='order_create'),
    path('order_detail/<int:order_id>/', order_detail, name='order_detail'),
    path('add_to_cart/<int:product_id>/', add_to_cart, name='add_to_cart'),
    path('remove_from_cart/<int:item_id>/', remove_from_cart, name='remove_from_cart')

]


from random import randint
from math import ceil
import Items
import Nodeclass
import enemyParty
# import Effects
# import os

class Player():
    race="human"
    name="stranger"
    max_movement_points=5
    movement_point=0
    maxEnergy=50
    curEnergy=maxEnergy
    worldmap=[]
    levelStage=1
    optionSettings=None
    equippedOH=None#Items.shield3 # off hand equipment
    equippedW=Items.weapon1#Items.weapon69 # Main hand equipment
    equippedA=Items.armour3
    stats={"STR":1,"END":1,"DIP":1,"DEX":1,"PER":1,"INT":1}
    skills={"One handed":25,"Two handed":5,"Throwing":5,"Shooting":5,"Blocking":5,"Heavy armour":5,"Medium armour":5,"Light armour":5,"Destruction magic":5,"Restoration magic":5}
    XP=0
    XPlevel=1
    XPcaps=(100,225,350,500,800,1300,1700,2400,3600,5000,10000)
    ability_points=10
    #Items.shield2,Items.potion1,Items.armour2,Items.weapon8,Items.shield2,Items.potion1,Items.armour2,Items.weapon8,Items.shield2,Items.potion1,Items.armour2,Items.weapon8
    Inventory=[Items.potion3]
    # effects=[]#{3:101},{15:101}
    enemiesOnMap=[]

    def __init__ (self,name,max_movement_points,maxHealth, gameSettings):
        self.name=name
        self.max_movement_points=max_movement_points
        self.movement_point=max_movement_points
        self.maxHealth=maxHealth
        self.curHealth=maxHealth
        self.maxHealth=maxHealth
        self.curHealth=maxHealth
        self.Y_cord=randint(1,gameSettings.DIMENTIONS-1)
        self.X_cord=randint(1,gameSettings.DIMENTIONS-1)
        self.money=100
        self.optionSettings=gameSettings
        # self.cooldown()

    def loadFromFile(self,file):

        self.race=file[0][1]
        self.name=file[0][2]
        self.levelStage=file[0][3]
        self.max_movement_points=file[0][4]
        self.maxEnergy=file[0][5]
        self.maxHealth=file[0][6]
        self.curHealth=file[0][7]
        self.XPlevel=file[0][8]

        self.equippedOH=file[0][9]
        for i in Items.listOfAllItems:
            if file[0][9] == i.name:
                self.equippedOH=i
                break
        self.equippedW=file[0][10]
        for i in Items.listOfAllItems:
            if file[0][10] == i.name:
                self.equippedW=i
                break
        self.equippedA=file[0][11]
        for i in Items.listOfAllItems:
            if file[0][11] == i.name:
                self.equippedA=i
                break

        self.ability_points=file[0][14]
        self.money=file[0][15]
        self.XP=file[0][16]
        NamesInventory=file[0][17].split("/")
        NamesInventory=NamesInventory[1:]
        self.Inventory=[]
        for i in NamesInventory:
            for j in Items.listOfAllItems:
                if i==j.name:
                    self.Inventory.append(j)

        statsHolder=file[0][12].split("/")
        statsHolder=statsHolder[1:]

        skillHolder=file[0][13].split("/")
        skillHolder=skillHolder[1:]

        for i,j in zip(statsHolder,self.stats):
            self.stats[j]=int(i)

        for i,j in zip(skillHolder,self.skills):
            self.skills[j]=int(i)

        mapHolder = file[0][18].split("/")
        grid = []
        self.enemiesOnMap=[]
        gap = self.optionSettings.WIDTH // self.optionSettings.DIMENTIONS
        count=0
        for i in range(self.optionSettings.DIMENTIONS):

            grid.append([])
            for j in range(self.optionSettings.DIMENTIONS):
                node = Nodeclass.Node(i, j, gap, self.optionSettings.DIMENTIONS)

                node.terrain=mapHolder[count][0]
                node.occupied=mapHolder[count][1]
                if node.occupied == "1":
                    print(node.row-1)
                    self.X_cord=node.row
                    self.Y_cord=node.col

                elif node.occupied == "2":
                    EP=enemyParty.EnemyParty(randint(1, self.optionSettings.DIMENTIONS-1), randint(0, self.optionSettings.DIMENTIONS-1),1)
                    EP.startnode=node
                    self.enemiesOnMap.append(EP)

                count+=1

                grid[i].append(node)
        self.worldmap = grid

    def reset(self):#when battle ends it resstes the map and position for the next fight
        self.curHealth=self.maxHealth

    def atribute_poins(self):#player updates his atribute points or checks his stats

        print("XP {}/{}\nLevel {}\nAtribute points {}".format(self.XP,self.XPcaps[self.XPlevel-1],self.XPlevel,self.ability_points))

        print("your skills are:")
        for i in self.skills: #prints all skills
            print(i,Player.skills[i])

        print("STATS:\n1. Strenght: {}\n2. Endurance: {}\n3. Deplomacy: {}\n4. Dexterity: ".format(Player.stats["STR"],Player.stats["END"],Player.stats["DIP"],Player.stats["DEX"],Player.stats["PER"],Player.stats["INT"]))

        while self.ability_points != 0:# if you have

            print("available points ".format(self.ability_points))
            print("STATS:\n1. Strenght: {}\n2. Endurance: {}\n3. Deplomacy: {}\n4. Dexterity: {}".format(Player.stats["STR"],Player.stats["END"],Player.stats["DIP"],Player.stats["DEX"]))
            izb=input("Whith stat do you wnat to increase?\nInput the corespoding number!")

            if izb=='1':#ups a chosen stat
                Player.stats["STR"]+=1
                self.ability_points-=1

            elif izb=='2':
                Player.stats["END"]+=1
                self.ability_points-=1
                self.maxHealth+=10

            elif izb=='3':
                Player.stats["DIP"]+=1
                self.ability_points-=1

            elif izb=='4':
                Player.stats["DEX"]+=1
                self.ability_points-=1
                self.max_movement_points+=1
        lol=input("Input E or e to exit")

    def Inventory_manage(self,Called_from):
        while True:
            print("gold: {}\n\nWearing {}\nMain hand {}\nOff hand {}\nhealth {}/{}\n".format(self.money,self.equippedA,self.equippedW,self.equippedOH,self.curHealth,self.maxHealth))

            for i in self.Inventory:
                print(i,"/ Value: ",i.value)
            izbor=int(input("\n1.Change armor\n2.Change weapon\n3.Use consumable\n4.Unequipn\n5.Delete item\n6.Exit\nInput the corespoding number or any other number to exit"))
            if izbor==1 :
                try:
                    available=[n for n in self.Inventory if isinstance(n,Items.C_armour)]
                    counter=0
                    for i in available:
                        print(counter,i,"/ Protection: ",i.defence,"/ Value: ",i.value )
                        counter+=1
                    izb_armor=input("Input the corespoding number or any other number to exit\n")
                    if self.equippedA!=None:
                        self.Inventory.append(self.equippedA)
                        self.equippedA=available[int(izb_armor)]
                        del self.Inventory[self.Inventory.index(available[int(izb_armor)])]
                    else:
                        self.equippedA=available[int(izb_armor)]
                        del self.Inventory[self.Inventory.index(available[int(izb_armor)])]
                except:
                    print("error")

            elif izbor==2:
                available=[n for n in self.Inventory if isinstance(n,Items.M_weapons) or isinstance(n,Items.C_shield) or isinstance(n,Items.R_weapons)]
                counter=0
                for i in available:
                    if isinstance(i,Items.R_weapons) or isinstance(i,Items.M_weapons) :
                        print(counter,i,"/ Power: ",i.damage,"/ Hands to use with:",i.hands,"/ Value: ",i.value)
                    else: print(counter,i,"/ Defence: ",i.defence,"/ Value: ",i.value)
                    counter+=1
                izb_weapon=input("Input the corespoding number\n")
                  #2 hands
                if available[int(izb_weapon)].hands == 2:
                    if self.equippedW != None:
                        self.Inventory.append(self.equippedW)
                    if self.equippedOH != None:
                        self.Inventory.append(self.equippedOH)
                    self.equippedW=available[int(izb_weapon)]
                    self.equippedOH=None
                    del self.Inventory[self.Inventory.index(available[int(izb_weapon)])]
                    #onehand
                else:
                    if isinstance(available[int(izb_weapon)],Items.C_shield):
                        if self.equippedW != None and self.equippedW.hands==2:
                            self.Inventory.append(self.equippedW)
                            self.equippedW=None
                            self.equippedOH = available[int(izb_weapon)]
                            del self.Inventory[self.Inventory.index(available[int(izb_weapon)])]
                        else:
                            if self.equippedOH != None:
                                self.Inventory.append(self.equippedOH)
                            self.equippedOH = available[int(izb_weapon)]
                            del self.Inventory[self.Inventory.index(available[int(izb_weapon)])]
                    else:
                        izb_hand=input("\nDo you want to equip on main or off hand\n1.Main 2.Off hand")
                        if izb_hand == '1':
                            if self.equippedW != None:
                                self.Inventory.append(self.equippedW)
                            self.equippedW = available[int(izb_weapon)]
                            del self.Inventory[self.Inventory.index(available[int(izb_weapon)])]
                        elif izb_hand == '2':
                            if self.equippedW != None and self.equippedW.hands == 2:
                                self.Inventory.append(self.equippedW)
                                self.equippedW = None
                                self.equippedOH = available[int(izb_weapon)]
                                del self.Inventory[self.Inventory.index(available[int(izb_weapon)])]
                            else:
                                if self.equippedOH != None:
                                    self.Inventory.append(self.equippedOH)
                                self.equippedOH = available[int(izb_weapon)]
                                del self.Inventory[self.Inventory.index(available[int(izb_weapon)])]

            elif izbor==3:
                available=[n for n in self.Inventory if isinstance(n,Items.C_consumable)]
                counter=0
                for i in available:
                    print(counter,i)
                    counter+=1
                izb_consum=input("Input the corespoding number\n")
                available[int(izb_consum)].use(self)
                del self.Inventory[self.Inventory.index(available[int(izb_consum)])]

            elif izbor==4:
                izb_uniq=input("1. Wearing: {}\n2. weaponMH: {}\n3. weaponOH: {}".format(self.equippedA,self.equippedW,self.equippedOH))
                if izb_uniq == '1':
                    if self.equippedA != None:
                        self.Inventory.append(self.equippedA)
                        self.equippedA = None

                    else: print("nothing to unequip")

                elif izb_uniq == '2':
                    if self.equippedW != None:
                        self.Inventory.append(self.equippedW)
                        self.equippedW = None

                    else: print("nothing to unequip")

                elif izb_uniq == '3':
                    if self.equippedOH != None:
                        self.Inventory.append(self.equippedOH)
                        self.equippedOH = None

                    else: print("nothing to unequip")

            elif izbor == 5:
                counter=0
                for i in self.Inventory:
                    print(counter,i)
                    counter+=1
                izb_delete=input("Input the corespoding number\n")
                conformation=input("are you susre you whant to delete {} \n1.Yes \n2.No".format(self.Inventory[int(izb_delete)]))
                if conformation == '1':
                    del self.Inventory[int(izb_delete)]
            elif izbor == 6:
                break

    def Dodege_chance(self):#s kakvo si oblechen,desxterity i level i se sravnqva sus hitchance na enemito
        #genirates a dodge chance the be pitted aginst enemie's hit chanse
        if self.equippedA == None:
            hitchanse=randint(7,12)+self.stats["DEX"]

        elif self.equippedA.armour_type == 'L' or self.equippedA.armour_type == 'C':
            hitchanse=randint(5,10)+self.stats["DEX"]+randint(0,self.skills["Light armour"]//6)

        elif self.equippedA.armour_type == 'M':
            hitchanse=randint(3,7)+self.stats["DEX"]+randint(0,self.skills["Medium armour"]//8)

        elif self.equippedA.armour_type == 'H':
            hitchanse=randint(0,5)+self.stats["DEX"]+randint(0,self.skills["Heavy armour"]//10)

        return (hitchanse+self.XPlevel)

    def Hit_chance(self):#genirates a hit chance to be pitted aginst enemy's dodge and block chance
        hitchanse=randint(1,21)

        if self.equippedW != None and isinstance(self.equippedW, Items.R_weapons):#used only if player uses a ranged weapon
            return hitchanse+self.XPlevel+ceil(self.stats["PER"]/2)

        else:
            if self.equippedW != None and self.equippedW.damage_type=='P' and hitchanse+5>=20:# used if player has a pearsing weapon, they have a crit bonus
                hitchanse+=5

            if hitchanse == 20:#the chance to genirate a crit chach is 1/20
                return 1000

            return hitchanse+self.XPlevel+ceil(self.stats["DEX"]/2)#returns the value

    def cooldown(self):#used to recet thing like movement points for the next tirn
        print("vleze")
        self.movement_points=self.max_movement_points

    def genirate_damage(self): #genirates damage and ups a skill if luky

        skillDamage=0# genirates bonus weapon skill damage
            #for 1 hand
        if self.equippedW != None and self.equippedW.hands == 1:
            if isinstance(self.equippedW, Items.M_weapons):
                skillDamage=self.skills["One handed"]//10
            else:
                skillDamage=self.skills["Throwing"]//10
            #for 2 hands
        elif self.equippedW != None and self.equippedW.hands == 2:
            if isinstance(self.equippedW, Items.M_weapons):
                skillDamage=self.skills["Two handed"]//10
            else:
                skillDamage=self.skills["Shooting"]//10

            #for off hand
        if self.equippedOH != None:
            if isinstance(self.equippedOH, Items.M_weapons):
                skillDamage=self.skills["One handed"]//10
            elif isinstance(self.equippedOH,Items.R_weapons):
                skillDamage=self.skills["Throwing"]//10

        if self.equippedW==None:#if you have nothing equiped you return this value
            return randint(1,4)+self.stats["STR"]
        else: return randint(1,3)+randint(1,self.equippedW.damage)+self.stats["STR"]+skillDamage

    def genirate_damage_offhand(self):#used to genirare off hand damage
        if self.equippedOH==None or isinstance(self.equippedOH, Items.C_shield):#if there is no off hand weapon the namage is genirated
            return 0

        else:
            return (randint(1,3)+self.equippedOH.damage+self.stats["STR"])//2

    def Block_chance(self):
            if isinstance(self.equippedOH, Items.C_shield):#if player has a shield this is used
                return randint(self.equippedOH.defence//2,self.equippedOH.defence)+randint(0,self.skills["Blocking"]//8)

            else: #if player has no shiled this is used
                return randint(0,5)+randint(0,self.skills["Blocking"]//10)

    def take_damage(self, enemy, crit = None):#when the player takes damage this is used
        damage=enemy.genirate_damage()#enemy genirates damage
        off_damage=enemy.genirate_damage_offhand()#genirates off hand damage if any

        if crit != None:#if the damege is critical the damage is multiplied by 2(determinade by enemy hit chanse)
            damage*=2

        if self.equippedA != None and (enemy.equippedW!=None and enemy.equippedOH!=None):
            #diermins if there is a bonus damage based on the armour that player is wearing
            if self.equippedA.armour_type == 'H' and enemy.equippedW.damage_type == 'B':
                print("using a blunt weapon extdadamage")
                damage*=1.25

            elif self.equippedA.armour_type == 'H' and enemy.equippedW.damage_type == 'S':
                print("using a sword agains heavy armour")
                damage*=0.75

            elif self.equippedA.armour_type == 'L' and enemy.equippedW.damage_type == 'S':
                print("using a sword agains light armour")
                damage*=1.25

            if off_damage != 0:
                if self.equippedA.armour_type == 'H' and enemy.equippedOH.damage_type == 'B':
                    print("using a blunt weapon extdadamage")
                    off_damage*=1.25

                elif self.equippedA.armour_type == 'H' and enemy.equippedOH.damage_type == 'S':
                    print("using a sword agains heavy armour")
                    off_damage*=0.75

                elif self.equippedA.armour_type == 'L' and enemy.equippedOH.damage_type == 'S':
                    print("using a sword agains light armour")
                    off_damage*=1.25

                    #armour absorbs some of the damage
            if (damage+off_damage)-self.equippedA.defence//2 <=0:
                print(self.equippedA.name + " absorbes all the damage!")
            else:
                print(self.equippedA.name + " blocks "+ str((damage+off_damage)-self.equippedA.defence//2) + " damage!")
                self.curHealth-=(damage+off_damage)-self.equippedA.defence//2

        else:
            self.curHealth-=(damage+off_damage)*2

        #ima shans da uvelichi nqkoi stat
        increase=randint(0,10)
        if increase == 0 and self.equippedA != None and self.equippedA.armour_type=='L':
            self.skills["Light armour"]+=1

        elif increase == 0 and self.equippedA != None and self.equippedA.armour_type=='M':
            self.skills["Medium armour"]+=1

        elif  increase == 0 and self.equippedA != None and self.equippedA.armour_type=='H':
            self.skills["Heavy armour"]+=1

        if self.equippedOH!= None and isinstance(self.equippedOH, Items.C_shield):
                self.skills["Blocking"]+=1

    def compressDictValues(self,toBeComp):#used to compress the skills and stats of the player in to a string that is used to represt starts in a databace
        compressed=""
        for i in list(toBeComp.values()):
            compressed+="/"+str(i)
        return compressed

    def compressInventory(self):#used to compress the inventory of th e player into a string usig the item id's
        compressed=""
        for i in self.Inventory:
            compressed+="/"+str(i.name)
        return compressed

    def compressWorldmap(self):
        compressed=""
        for i in self.worldmap:
            for j in i:
                compressed+= j.terrain + j.occupied + "/"
        return compressed


"""
-------------------------------
Playbook configuration fixtures
-------------------------------
"""

# 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 pytest

from whale import config
from whale.decapod import steps

__all__ = [
    'get_playbook_config_steps',
    'playbook_config_steps',
    'playbook_config_deploy',
    'cleanup_playbook_configs',
]

@pytest.fixture(scope="session")
def get_playbook_config_steps(get_decapod_client):
    """Callable session fixture to get playbook configuration steps.

    Args:
        get_decapod_client (function): function to get decapod client

    Returns:
        function: function to get playbook configuration steps
    """
    def _get_steps():
        return steps.PlaybookConfigSteps(get_decapod_client())

    return _get_steps

@pytest.fixture
def playbook_config_steps(get_playbook_config_steps, cleanup_playbook_configs):
    """Function fixture to get playbook configuration steps.

    Args:
        get_playbook_config_steps (function): get playbook config steps
        cleanup_playbook_configs (function): function to cleanup
            playbook configs after test

    Yields:
        PlaybookConfigSteps: instantiated playbook config steps
    """
    _playbook_config_steps = get_playbook_config_steps()
    configs = _playbook_config_steps.get_playbook_configs(check=False)
    configs_ids_before = {conf['id'] for conf in configs}

    yield _playbook_config_steps

    cleanup_playbook_configs(_playbook_config_steps,
                             uncleanable_ids=configs_ids_before)

@pytest.fixture
def playbook_config_deploy(request,
                           cluster,
                           server_steps,
                           playbook_config_steps):
    """Function fixture to create playbook config before test.

    Args:
        request (obj): pytest SubRequest instance
        cluster (dict): model of cluster
        server_steps (fixture): fixture to get servers ids
        playbook_config_steps (obj): instantiated playbook config steps

    Returns:
        dict: model of new playbook configuration
    """
    options = {}
    hints = getattr(request, 'param', [])
    if hints:
        options['hints'] = hints

    playbook_id = config.PLAYBOOK_DEPLOY_CLUSTER
    server_ids = server_steps.get_server_ids()[0:config.DEPLOY_SERVERS_COUNT]
    return playbook_config_steps.create_playbook_config(
        cluster_id=cluster['id'],
        playbook_id=playbook_id,
        server_ids=server_ids,
        **options)

@pytest.fixture(scope='session')
def cleanup_playbook_configs():
    """"Callable session fixture to cleanup playbook configs.

    Returns:
        function: function to cleanup playbook configs
    """
    def _cleanup_playbook_configs(_playbook_config_steps,
                                  uncleanable_ids=None):
        uncleanable_ids = uncleanable_ids or []
        for config in _playbook_config_steps.get_playbook_configs(check=False):
            if config['id'] not in uncleanable_ids:
                _playbook_config_steps.delete_playbook_config(config['id'])

    return _cleanup_playbook_configs