"""
Main flask endpoints for this application.

Project: QuasselFlask
"""

import time

from flask import Response, flash, request, g, render_template, url_for, redirect
from flask_sqlalchemy import get_debug_queries
from flask_user import login_required, current_user
from sqlalchemy.orm import joinedload
from werkzeug.exceptions import BadRequest, NotFound

import quasselflask
from quasselflask import app, db, userman
from quasselflask.adapters import ghostlid
from quasselflask.adapters.email_adapter import send_confirm_email_email
from quasselflask.models.query import *
from quasselflask.parsing.form import process_search_params, SearchType
from quasselflask.parsing.irclog import DisplayBacklog, DisplayUserSummary
from quasselflask.util import safe_redirect, get_next_url, log_access, log_action, log_action_error, repr_user_input

logger = app.logger  # type: logging.Logger

@app.context_processor
def inject_themes():
    themeid = current_user.themeid
    default_themeid = app.config.get('QF_DEFAULT_THEME', 0)
    themes_dict = app.config.get('QF_THEMES', {})
    theme = themes_dict.get(themeid, default_themeid)
    return dict(user_theme=theme, themes=themes_dict)

@app.context_processor
def inject_search():
    """
    Inject search variables/constants universal to search form-based templates.
    :return:
    """
    return dict(SearchType=SearchType)

@app.before_first_request
def flask_user_redirect_patch():
    """
    HACK: Replace werkzeug redirect() with a safe version globally at runtime

    This is a workaround for Flask-User <0.6.8, which upon login, logout, etc. will redirect according to the 'next'
    GET parameter without validating it and thus presents an open redirect security risk. As a solution, we will
    globally replace the redirect() function in werkzeug with a safety-checked one.

    The original method is available as werkzeug.util.unsafe_redirect.
    """
    import flask_user.views
    flask_user.views.unsafe_redirect = flask_user.views.redirect
    flask_user.views.redirect = flask_user.views.safe_redirect = safe_redirect

@app.before_first_request
def qf_setup_themes():
    """ Reads the theme config (default and custom) and generates the structures used by the template. """
    from quasselflask.views.themes import Theme

    themes_dict = {}
    for id_, name, file, cls in app.config.get('QF_DEFAULT_THEMES', []):
        theme = Theme(id_, name, file=file, root_class=cls)
        themes_dict[theme.id] = theme
    for id_, name, file, cls in app.config.get('QF_CUSTOM_THEMES', []):
        theme = Theme(id_, name, file=file, root_class=cls, custom=True)
        themes_dict[theme.id] = theme
    app.config['QF_THEMES'] = themes_dict

@app.before_request
def globals_init():
    g.start_time = time.time()
    g.get_request_time = lambda: "{:.3f}s".format(time.time() - g.start_time)
    g.display_version = quasselflask.__version__

@app.before_request
def request_log_access():
    if request.endpoint != 'static':
        logger.info(log_access())

@app.route('/')
@login_required
def home():
    return render_template('search_form.html')

@app.route('/search/logs')
@login_required
def search():
    # process the args passed in from the query string in the request
    # this also documents the POST form parameters - check this method's source along with the readme
    try:
        sql_args, render_args = _process_search_form_params()
        sql_args['limit'] += 1  # so we know if there are more results
    except BadRequest:
        return redirect(url_for('home'))

    render_args['search_type'] = SearchType.backlog

    # build and execute the query
    results_cursor = build_query_backlog(db.session, sql_args,
                                         query_options=(joinedload(Backlog.sender),
                                                        joinedload(Backlog.buffer).joinedload(Buffer.network))).all()

    # reversed() if we're doing newest-first because we still want chronological order
    if sql_args['order'] == 'newest':
        results_raw = list(reversed(results_cursor))
    else:
        results_raw = list(results_cursor)

    # check if we have more results available than the passed limit (note that we queried for limit+1 results)
    render_args['more_results'] = False
    if len(results_raw) == sql_args['limit']:  # this limit was already incremented
        results_raw = results_raw[0:-1]  # only show up to the user-entered limit
        render_args['more_results'] = True  # for template

    # set up display
    results_display = [DisplayBacklog(result) for result in results_raw]
    render_args['search_results_total'] = len(results_display)

    if (app.debug or app.testing) and get_debug_queries():
        for info in get_debug_queries():
            app.logger.debug("SQL: {}\nParameters: {}\nDuration: {:.3f}s\n\n".format(
                info.statement, repr(info.parameters), info.duration))

    render_args['expand_line_details'] = _is_expand_line_details(sql_args, results_raw)

    return render_template('results.html', records=results_display, **render_args)

def _do_search_text() -> str:
    """
    Execute a search and return results as text. This is shared between endpoints.
    :return:
    """
    # process the args passed in from the query string in the request
    # this also documents the POST form parameters - check this method's source along with the readme
    try:
        sql_args, _ = _process_search_form_params()
    except BadRequest:
        return Response('400 Bad Request', status=400, mimetype='text/plain')

    # build and execute the query
    results_cursor = build_query_backlog(db.session, sql_args,
                                         query_options=(joinedload(Backlog.sender),
                                                        joinedload(Backlog.buffer).joinedload(Buffer.network))).all()

    # reversed() if we're doing newest-first because we still want chronological order
    if sql_args['order'] == 'newest':
        results_raw = list(reversed(results_cursor))
    else:
        results_raw = list(results_cursor)

    # set up display
    results_display = [DisplayBacklog(result) for result in results_raw]
    expand_line_details = _is_expand_line_details(sql_args, results_raw)
    results_text = render_template('results.txt', records=results_display, expand_line_details=expand_line_details)
    return results_text

@app.route('/search/logs/text')
@login_required
def search_text():
    return Response(_do_search_text(), mimetype='text/plain', status=200)

@app.route('/search/logs/paste/<duration>', methods=['POST'])
@login_required
def search_paste(duration):
    if not duration or len(duration) > 6:
        raise BadRequest('Invalid duration value.')

    results_text = _do_search_text()
    url = ghostlid.paste(results_text, expire=duration)
    return Response(url, mimetype='text/plain', status=200)

@app.route('/search/users')
@login_required
def search_users():
    # process the args passed in from the query string in the request
    # this also documents the POST form parameters - check this method's source along with the readme
    try:
        sql_args, render_args = _process_search_form_params()
        # not doing the +1 trick to check if more results, because of the grouping+summing that happens here
    except BadRequest:
        return redirect(url_for('home'))

    render_args['search_type'] = SearchType.usermask

    # build and execute the query
    results_cursor = build_query_usermask(db.session, sql_args).all()

    if (app.debug or app.testing) and get_debug_queries():
        info = get_debug_queries()[0]
        app.logger.debug("SQL: {}\nParameters: {}\nDuration: {:.3f}s".format(
            info.statement, repr(info.parameters), info.duration))

    results_raw = list(results_cursor)
    results_display = [DisplayUserSummary(sender, count) for sender, count in results_raw]
    render_args['search_results_total'] = sum(record.count for record in results_display)

    return render_template('results_users.html', records=results_display, **render_args)

def _do_search_users_text():
    # process the args passed in from the query string in the request
    try:
        sql_args, render_args = _process_search_form_params()
    except BadRequest:
        return Response('400 Bad Request', status=400, mimetype='text/plain')

    # build and execute the query
    results_cursor = build_query_usermask(db.session, sql_args).all()
    results_raw = list(results_cursor)
    results_display = [DisplayUserSummary(sender, count) for sender, count in results_raw]
    render_args['search_results_total'] = sum(record.count for record in results_display)
    render_args['col_len_nickname'] = max(len(record.nickname) for record in results_display)
    render_args['col_len_sender'] = max(len(record.sender) for record in results_display)
    render_args['col_len_count'] = max(len(str(record.count)) for record in results_display)
    results_text = render_template('results_users.txt', records=results_display, **render_args)
    return results_text

@app.route('/search/users/text')
@login_required
def search_users_text():
    return Response(_do_search_users_text(), mimetype='text/plain', status=200)

@app.route('/search/users/paste/<duration>', methods=['POST'])
@login_required
def search_users_paste(duration):
    if not duration or len(duration) > 6:
        raise BadRequest('Invalid duration value.')

    results_text = _do_search_text()
    url = ghostlid.paste(results_text, expire=duration)
    return Response(url, mimetype='text/plain', status=200)

def _process_search_form_params() -> (dict, dict):
    """
    Process the params in request.args. This method is a wrapper method that a) outputs useful debugging messages; and
    b) returns both the processed SQL parameters, and the sanitized "display" parameters that can be passed to the
    template to prepopulate the form.
    :return: Two dicts: first is sql args, second is render (template) args after sanitisation. See ``search()`` for
        example usage of this function.
    :raise BadRequest: set of search parameters is invalid
    """
    # some helpful constants for the request argument processing
    # type of extraction/processing - this is more documentation as it's not used to process at the moment
    unique_args = {'start', 'end', 'limit', 'query_wildcard'}
    list_wildcard_args = {'channel', 'usermask'}  # space-separated lists; if any arg repeated, list is concatenated
    query_args = {'query'}  # requires query parsing
    search_args = unique_args | list_wildcard_args | query_args

    form_args = request.args
    available_args = search_args & set(form_args.keys())

    # if no arguments passed, we can just redirect to the home
    if not available_args:
        raise BadRequest("Invalid search: no search parameters")

    # For rendering in templates - will be updated after processing search params (if successful) before render
    render_args = {
        'search_channel': form_args.get('channel'),
        'search_usermask': form_args.get('usermask'),
        'search_start': form_args.get('start'),
        'search_end': form_args.get('end'),
        'search_query': form_args.get('query'),
        'search_query_wildcard': form_args.get('search_query_wildcard', int),
        'search_limit': form_args.get('limit', app.config['RESULTS_NUM_DEFAULT'], int),
        'search_order': form_args.get('order'),
        'search_type': form_args.get('type'),
        'expand_line_details': False,
    }

    # Process and parse the args
    try:
        sql_args = process_search_params(form_args)
        sql_args['permissions'] = query_permitted_buffers(db.session, current_user)
    except ValueError as e:
        errtext = e.args[0]
        return render_template('search_form.html', error=errtext, **render_args)

    app.logger.debug("Args|SQL: limit=%i order=%s channel%s usermask%s start[%s] end[%s] query%s %s",
                     sql_args['limit'], sql_args['order'], sql_args['channels'], sql_args['usermasks'],
                     sql_args['start'].isoformat() if sql_args['start'] else '',
                     sql_args['end'].isoformat() if sql_args['end'] else '',
                     sql_args['query'].get_parsed(), '[wildcard]' if sql_args['query_wildcard'] else '[no_wildcard]')

    app.logger.debug("Permissions: {}".format(', '.join(str(pbuf.bufferid) for pbuf in sql_args['permissions'])))

    # update after processing params
    render_args['search_query_wildcard'] = sql_args.get('query_wildcard')
    render_args['search_limit'] = sql_args.get('limit')
    render_args['search_order'] = sql_args.get('order')
    render_args['search_type'] = sql_args.get('type')
    return sql_args, render_args

def _is_expand_line_details(sql_args: dict, results: [Backlog]) -> bool:
    """
    Check the query and results to see if the backlog results should be expanded by default.

    Default expansion should happen when results may preserve discussion sequence (e.g. a usermask or keyword search),
    or contain results from multiple channels.

    :param sql_args:
    :param results:  raw results from the query
    :return:
    """
    # get unique channels and users by ID
    # efficiency note for big result sets: set() type uses hashing for fast "x in s" operations, and
    # set.add() won't add redundant entries - so this yields sets of unique channels/users.
    result_users = set()
    result_channels = set()
    for result in results:
        result_users.add(result.senderid)
        result_channels.add(result.bufferid)

    # determine some display settings based on the type of query made
    has_single_channel = (len(result_channels) == 1)
    is_user_search = bool(sql_args.get('usermasks'))
    is_keyword_search = bool(sql_args.get('query').postfix)
    return (not has_single_channel) or is_user_search or is_keyword_search

@app.route('/user/permissions', methods=['GET'])
@login_required
def check_permissions():
    """
    Shows a list of permitted buffers.
    :return:
    """
    permitted_buffers = query_permitted_buffers(db.session, current_user)
    return render_template("check_permissions.html", user=current_user, buffers=permitted_buffers)

# TODO: 'next' parameter hack - add version check on Flask-User version

@app.route('/user/update', methods=['POST'])
@login_required
def user_update():
    """
    Update current user's information. Any fields not included will remain unchanged.

    Some actions return a confirmation page. It is necessary to submit the confirmation form to complete the action.

    If acting on the current user, only the email address may be updated.  This prevents the current user from locking
    themselves out of the application or removing a sole superuser.

    POST command parameter (exactly one required):

    * `email`: new email address. This will require the user to reconfirm their email address before their account is
        re-enabled.
    * `themeid`: new theme ID (int).

    Other POST parameters, common to all requests:

    * `next`: URL, the URL to return to after the update.

    :return:
    """

    commands = frozenset(('email', 'themeid'))
    request_commands = set(request.form.keys()) & commands

    # validate
    request_valid = len(request_commands) == 1

    if not request_valid:
        raise BadRequest("No command or multiple commands to user update API endpoint")

    # Valid - let's process it
    user = current_user  # laziness and because this mirrors the admin_update_user endpoint

    if 'email' in request_commands:
        try:
            user.email = request.form.get('email')
            if userman.enable_confirm_email:
                user.confirmed_at = None

            # confirmation email
            send_confirm_email_email(user)

            db.session.commit()
            flash('Updated email to {email} (must re-confirm to reactivate account)'.format(email=user.email), 'notice')
            logger.info(log_action('update user', ('set', 'email'), ('email', user.email)))
            return safe_redirect(get_next_url('POST'))
        except Exception as e:
            logger.error(log_action_error('error while updating user profile', repr(e.args),
                                          ('id', user.qfuserid), ('name', user.username),
                                          ('email', user.email), ('superuser', repr(user.superuser))), exc_info=True)
            db.session.rollback()
            if app.debug:
                raise  # let us debug this
            else:
                flash('Error occurred while updating user. Please try again later, or contact the server administrator '
                      'with the date/time of this error and your IP address in order to trace error information in the'
                      'logs.')
                return safe_redirect(get_next_url('POST'))

    elif 'themeid' in request_commands:
        try:
            newid = int(request.form.get('themeid'))
        except ValueError:
            newid = None

        logger.debug(repr(app.config['QF_THEMES']))
        logger.debug(repr(newid))
        if newid in app.config['QF_THEMES']:
            user.themeid = newid
            db.session.commit()
            return safe_redirect(get_next_url('POST'))
        else:
            raise BadRequest("Invalid theme ID.")

    flash("Something happened. You shouldn't have gotten this far.", "error")
    logger.error(log_action_error('user update', 'should have returned earlier in code - bug?'))
    logger.debug('request.form=' + repr_user_input(request.form))
    return safe_redirect(get_next_url('POST'))

@app.route('/context/<int:post_id>/<int:num_context>')
def context(post_id, num_context):
    pass  # TODO context endpoint


import xml.etree.ElementTree as ET

import pytest

from asciidoxy.parser.doxygen.language_traits import TokenCategory
from asciidoxy.parser.doxygen.objc import ObjectiveCTypeParser
from asciidoxy.parser.doxygen.type_parser import Token, TypeParseError
from tests.unit.matchers import IsEmpty, IsNone, m_typeref
from tests.unit.shared import sub_element

from .test_type_parser import (
    arg_name,
    args_end,
    args_sep,
    args_start,
    name,
    operator,
    qualifier,
    sep,
    whitespace,
)

@pytest.fixture(params=[
    "",
    "nullable ",
    "const ",
    "__weak ",
    "__strong ",
    "nullable __weak ",
    "nullable __strong ",
    "_Nonnull ",
    "_Nullable ",
    "__nonnull ",
])
def objc_type_prefix(request):
    return request.param

@pytest.fixture(
    params=["", " *", " **", " * *", " * _Nonnull", " * _Nullable", "*_Nonnull*__autoreleasing"])
def objc_type_suffix(request):
    return request.param

def test_parse_objc_type_from_text_simple(driver_mock, objc_type_prefix, objc_type_suffix):
    type_element = ET.Element("type")
    type_element.text = f"{objc_type_prefix}NSInteger{objc_type_suffix}"

    m_typeref(
        id=IsNone(),
        kind=IsNone(),
        language="objc",
        name="NSInteger",
        prefix=objc_type_prefix,
        suffix=objc_type_suffix,
        nested=IsEmpty(),
    ).assert_matches(ObjectiveCTypeParser.parse_xml(type_element, driver=driver_mock))
    driver_mock.assert_unresolved()  # built-in type

@pytest.mark.parametrize("type_with_space", [
    "short int",
    "signed short",
    "signed short int",
    "unsigned short",
    "unsigned short int",
    "signed int",
    "unsigned int",
    "long int",
    "signed long",
    "signed long int",
    "unsigned long",
    "unsigned long int",
    "long long",
    "long long int",
    "signed long long",
    "signed long long int",
    "unsigned long long",
    "unsigned long long int",
    "signed char",
    "long double",
    "unsigned char",
    "signed char",
])
def test_parse_objc_type_with_space(driver_mock, type_with_space):
    type_element = ET.Element("type")
    type_element.text = type_with_space

    m_typeref(
        id=IsNone(),
        kind=IsNone(),
        language="objc",
        name=type_with_space,
        prefix=IsEmpty(),
        suffix=IsEmpty(),
        nested=IsEmpty(),
    ).assert_matches(ObjectiveCTypeParser.parse_xml(type_element, driver=driver_mock))
    driver_mock.assert_unresolved()  # built-in type

def test_parse_objc_type__array(driver_mock):
    type_element = ET.Element("type")
    type_element.text = "MyType[]"

    m_typeref(
        name="MyType",
        prefix=IsEmpty(),
        suffix="[]",
    ).assert_matches(ObjectiveCTypeParser.parse_xml(type_element, driver=driver_mock))
    driver_mock.assert_unresolved("MyType")

def test_parse_objc_type__array__with_size(driver_mock):
    type_element = ET.Element("type")
    type_element.text = "MyType[16]"

    m_typeref(
        name="MyType",
        prefix=IsEmpty(),
        suffix="[16]",
    ).assert_matches(ObjectiveCTypeParser.parse_xml(type_element, driver=driver_mock))
    driver_mock.assert_unresolved("MyType")

def test_parse_objc_type__array__with_prefix_and_suffix(driver_mock):
    type_element = ET.Element("type")
    type_element.text = "const MyType[]*"

    m_typeref(
        name="MyType",
        prefix="const ",
        suffix="[]*",
    ).assert_matches(ObjectiveCTypeParser.parse_xml(type_element, driver=driver_mock))
    driver_mock.assert_unresolved("MyType")

def test_parse_objc_type__array__as_nested_type(driver_mock):
    type_element = ET.Element("type")
    type_element.text = "id<MyType[]>"

    m_typeref(
        name="id",
        prefix=IsEmpty(),
        suffix=IsEmpty(),
        nested=[
            m_typeref(
                name="MyType",
                prefix=IsEmpty(),
                suffix="[]",
            ),
        ],
    ).assert_matches(ObjectiveCTypeParser.parse_xml(type_element, driver=driver_mock))
    driver_mock.assert_unresolved("MyType")

def test_parse_objc_type__array__brackets_inside_name_element(driver_mock):
    type_element = ET.Element("type")
    sub_element(type_element, "ref", refid="tomtom_mytype", kindref="compound", text="MyType[]")
    ET.dump(type_element)

    m_typeref(
        id="objc-tomtom_mytype",
        name="MyType",
        prefix=IsEmpty(),
        suffix="[]",
    ).assert_matches(ObjectiveCTypeParser.parse_xml(type_element, driver=driver_mock))
    driver_mock.assert_unresolved()

def test_parse_objc_type__array__multiple_brackets_inside_name_element(driver_mock):
    type_element = ET.Element("type")
    sub_element(type_element, "ref", refid="tomtom_mytype", kindref="compound", text="MyType[][]")
    ET.dump(type_element)

    m_typeref(
        id="objc-tomtom_mytype",
        name="MyType",
        prefix=IsEmpty(),
        suffix="[][]",
    ).assert_matches(ObjectiveCTypeParser.parse_xml(type_element, driver=driver_mock))
    driver_mock.assert_unresolved()

def test_parse_objc_type__array__with_size_inside_name_element(driver_mock):
    type_element = ET.Element("type")
    sub_element(type_element, "ref", refid="tomtom_mytype", kindref="compound", text="MyType[12]")
    ET.dump(type_element)

    m_typeref(
        id="objc-tomtom_mytype",
        name="MyType",
        prefix=IsEmpty(),
        suffix="[12]",
    ).assert_matches(ObjectiveCTypeParser.parse_xml(type_element, driver=driver_mock))
    driver_mock.assert_unresolved()

def test_parse_objc_type__array__end_bracket_without_start_inside_name_element(driver_mock):
    type_element = ET.Element("type")
    sub_element(type_element, "ref", refid="tomtom_mytype", kindref="compound", text="MyType]")
    ET.dump(type_element)

    with pytest.raises(TypeParseError):
        ObjectiveCTypeParser.parse_xml(type_element, driver=driver_mock)
    driver_mock.assert_unresolved()

def block(text: str = "^") -> Token:
    return Token(text, TokenCategory.BLOCK)

@pytest.mark.parametrize("tokens, expected", [
    ([], []),
    ([
        qualifier("nullable"),
        whitespace(),
        name("Type"),
        whitespace(),
        operator("*"),
    ], [
        qualifier("nullable"),
        whitespace(),
        name("Type"),
        whitespace(),
        operator("*"),
    ]),
    ([
        name("Type"),
        whitespace(),
        name("value"),
    ], [
        name("Type"),
        whitespace(),
        name("value"),
    ]),
    ([
        name("Type"),
        args_start(),
        name("OtherType"),
        whitespace(),
        name("value"),
        args_end(),
    ], [
        name("Type"),
        args_start(),
        name("OtherType"),
        whitespace(),
        arg_name("value"),
        args_end(),
    ]),
    ([
        name("Type"),
        args_start(),
        name("OtherType"),
        whitespace(),
        operator("*"),
        name("value"),
        args_end(),
    ], [
        name("Type"),
        args_start(),
        name("OtherType"),
        whitespace(),
        operator("*"),
        arg_name("value"),
        args_end(),
    ]),
    ([
        name("Type"),
        args_start(),
        name("OtherType"),
        whitespace(),
        operator("*"),
        name("value"),
        sep(),
        name("CoolType"),
        whitespace(),
        qualifier("nullable"),
        whitespace(),
        name("null_value"),
        args_end(),
    ], [
        name("Type"),
        args_start(),
        name("OtherType"),
        whitespace(),
        operator("*"),
        arg_name("value"),
        args_sep(),
        name("CoolType"),
        whitespace(),
        qualifier("nullable"),
        whitespace(),
        arg_name("null_value"),
        args_end(),
    ]),
    ([
        name("void"),
        args_start(),
        block(),
        args_end(),
        args_start(),
        name("NSString"),
        whitespace(),
        operator("*"),
        name("text"),
        args_end(),
    ], [
        name("void"),
        args_start(),
        name("NSString"),
        whitespace(),
        operator("*"),
        arg_name("text"),
        args_end(),
    ]),
],
                         ids=lambda ts: "".join(t.text for t in ts))
def test_objc_type_parser__adapt_tokens(tokens, expected):
    assert ObjectiveCTypeParser.adapt_tokens(tokens) == expected


sumDollar = float(input("John left /in dollars/ :"))
exRate = float(input("Excgange rate USD/LV:"))
pizzaPrice = float(input("Pizza price/lv/:"))
lsPrice = float(input("Lasagna price/lv/:"))
sandPrice = float(input("Sandwich price/lv/:"))
pizzaQantity = int(input("Pizza wants-to-eat:"))
lsQantity = int(input("Lasagna wants-to-eat:"))
sandQantity = int(input("Sandwich wants-to-eat:"))
sumLv = sumDollar *exRate

totalSum = pizzaPrice * pizzaQantity + lsPrice * lsQantity + sandPrice * sandQantity

if totalSum < sumLv :
    moneyLeft = (sumLv-totalSum)/exRate
    moneyLeft = round(moneyLeft, 2)
    print("Garfield is well fed, John is awesome. Money left: $", moneyLeft,end=".")
else:
    moneyLeft = (totalSum - sumLv) / exRate
    moneyLeft = round(moneyLeft, 2)
    print("Garfield is hungry. John is a badass. Money needed: $", moneyLeft,end=".")


# Online Python - IDE, Editor, Compiler, Interpreter
import random

import game_queue
import shared
import algorithm
import rating
import datetime
from typing import List
random.seed()

def get_lineup_debug_str(rt_queue_data, ct_queue_data):
    rt_player_data_str = get_player_data_str(rt_queue_data, ladder_type=shared.RT_LADDER)
    ct_player_data_str = get_player_data_str(ct_queue_data, ladder_type=shared.CT_LADDER)

    rt_best_lineups = algorithm.get_best_lineup_for_each_group(rt_queue_data)
    ct_best_lineups = algorithm.get_best_lineup_for_each_group(ct_queue_data)

    rt_best_lineup_str = get_best_lineups_str(rt_best_lineups, ladder_type=shared.RT_LADDER)
    ct_best_lineup_str = get_best_lineups_str(ct_best_lineups, ladder_type=shared.CT_LADDER)
    return rt_player_data_str, ct_player_data_str, rt_best_lineup_str, ct_best_lineup_str

def get_simulation_str(mllu_text: str):
    rt_player_list, ct_player_list = parse_mllu_text(mllu_text)
    rt_lounge_data = get_mmrs(rt_player_list, ladder_type=shared.RT_LADDER)
    ct_lounge_data = get_mmrs(ct_player_list, ladder_type=shared.CT_LADDER)
    return get_lineup_debug_str(rt_lounge_data, ct_lounge_data)

def parse_mllu_text(text: str):
    rt_player_list = set()
    ct_player_list = set()
    rt_flag = True
    for line in text.splitlines():
        players_to_add = []
        if "full mogi" in line or "active mogi" in line:
            pass
        elif "rt-tier" in line:
            rt_flag = True
            pass
        elif "ct-tier" in line:
            rt_flag = False
            pass
        elif "Last updated" in line or "This will update every" in line or line.strip() == "":
            pass
        elif line.startswith("Team"):
            players_text = line.split(":")[1].strip()
            players_to_add = players_text.split(", ")
        else:
            players_to_add = line.split(", ")

        if rt_flag:
            rt_player_list.update(players_to_add)
        else:
            ct_player_list.update(players_to_add)
    return list(rt_player_list), list(ct_player_list)

def get_mmrs(player_list, ladder_type: str):
    if len(player_list) == 0:
        return []

    new_player_list = []
    cur_time = datetime.datetime.now()
    for player_name in player_list:
        potential_addition = game_queue.Player.name_to_partial_player(player_name)
        player_rating = rating.get_player_rating(potential_addition.get_queue_key(), ladder_type)
        if player_rating is None:
            print(f"Could not find a {ladder_type} rating for {player_name}")
        else:
            min_queued = random.randrange(0, algorithm.MAX_QUEUE_TIME, 1)
            new_player_list.append(game_queue.Player(player_name,
                                                     player_rating[2],
                                                     player_rating[3],
                                                     cur_time - datetime.timedelta(minutes=min_queued),
                                                     False,
                                                     False,
                                                     0,
                                                     0,
                                                     cur_time)
                                   )

    return new_player_list

def get_best_lineups_str(best_lineups, ladder_type: str, header=True):
    text_str = ""
    if header:
        text_str = f"For each player, the best lineup for that player was computed. " \
                   f"Then, duplicate lineups were removed. {ladder_type.upper()} results:\n"
    if len(best_lineups) == 0:
        text_str += "None found\n"
    else:
        cur_time = datetime.datetime.now()
        for lineup in sorted(best_lineups, key=algorithm.compute_lineup_score):
            total_score, breakdown = algorithm.compute_lineup_score(lineup, breakdown=True)
            for descriptor in breakdown:
                if type(breakdown[descriptor]) == float:
                    breakdown[descriptor] = round(breakdown[descriptor], 3)
            total_score = round(total_score, 3)
            breakdown_str = '\n\t'.join([str(desc)+': '+str(val) for desc, val in breakdown.items()])
            lineup_str = "\n\t\t".join(get_player_str(p, cur_time) for p in sorted(lineup,
                                                                                key=lambda z: z.mmr, reverse=True)
                                       )
            text_str += f"Score: {total_score}\n\t{breakdown_str}\n\t\t{lineup_str}\n"

    return text_str + "\n-------------------------------------------------------------------------------\n"

def get_player_str(player: game_queue.Player, time_reference=None) -> str:
    time_reference = datetime.datetime.now() if time_reference is None else time_reference
    player_mmr_str = f"{player.mmr} MMR"
    return f"{player.name:<15} | {player_mmr_str:>9} | {algorithm.get_minutes(time_reference-player.time_queued):<3}" \
           f" minutes queued"

def get_player_data_str(queue: game_queue.Queue, ladder_type: str):
    text_str = f"{ladder_type.upper()} Data:"
    cur_time = datetime.datetime.now()
    for player in sorted(queue.get_players(), key=lambda z: z.mmr, reverse=True):
        text_str += f"\n{get_player_str(player, cur_time)}"
    return text_str


# Import default modules
from http.server import BaseHTTPRequestHandler, HTTPServer

# Import middlewares modules
from middlewares.database import connect    as middlewareDatabaseConnect
from middlewares.database import disconnect as middlewareDatabaseDisconnect
from middlewares          import request    as middlewareRequest
from middlewares          import routes     as middlewareRoutes
from middlewares          import access     as middlewareAccess
from middlewares          import response   as middlewareResponse

HTTP_HOST = '0.0.0.0'
HTTP_PORT = 8080

# Response
def response(http, database, cursor):
    http.send_header('Access-Control-Allow-Origin','*')
    http.send_header('Access-Control-Allow-Headers', 'Token, Content-Type')
    http.send_header('Access-Control-Allow-Methods', 'OPTIONS, GET, POST, PUT, DELETE')
    http.end_headers()

    if database is not None and cursor is not None:
        middlewareDatabaseDisconnect.run(database, cursor)

# Execute action
def execute(method, name, parametes, cursor):
    action = getattr(__import__('actions', None, None, [name]), name)

    result = getattr(action, method)(parametes, cursor)

    return {
        'code': result[0],
        'body': result[1],
    }

# Hanle action func
def handler(method, http):
    # Middleware request
    parameters = middlewareRequest.run(method, http)

    # Middleware routes
    action = middlewareRoutes.run(method, http)

    if action is None:
        response(http, None, None)

        return

    # Middleware database connect
    result = middlewareDatabaseConnect.run()

    database = result['database']
    cursor = result['cursor']

    # Middleware access
    result = middlewareAccess.run(http, method, cursor)

    if not result:
        response(http, database, cursor)

        return

    # Execute
    result = execute(method, action, parameters, cursor)

    # Middleware response
    middlewareResponse.run(method, http, result['code'], result['body'])

    # Middleware database disconnect
    middlewareDatabaseDisconnect.run(database, cursor)

# Hanle action class
class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        handler('GET', self)

    def do_POST(self):
        handler('POST', self)

    def do_PUT(self):
        handler('PUT', self)

    def do_DELETE(self):
        handler('DELETE', self)

    def do_OPTIONS(self):
        self.send_response(204)
        self.send_header('Access-Control-Allow-Origin','*')
        self.send_header('Access-Control-Allow-Headers', 'Token, Content-Type')
        self.send_header('Access-Control-Allow-Methods', 'OPTIONS, GET, POST, PUT, DELETE')
        self.end_headers()

# Run server
HTTPServer((HTTP_HOST, HTTP_PORT), Handler).serve_forever()


import requests
import os
from dotenv import load_dotenv

load_dotenv(verbose=True)

def get_translate(text):
    client_id = os.getenv("PAPAGO_ID")  # <-- client_id 기입
    client_secret = os.getenv("PAPAGO_SECRET")  # <-- client_secret 기입

    data = {'text': text,
            'source': 'en',
            'target': 'ko'}

    url = "https://openapi.naver.com/v1/papago/n2mt"

    header = {"X-Naver-Client-Id": client_id,
              "X-Naver-Client-Secret": client_secret}

    response = requests.post(url, headers=header, data=data)
    rescode = response.status_code

    if rescode == 200:
        send_data = response.json()
        print("sd",send_data)
        trans_data = send_data['message']['result']['translatedText']
        print("td", trans_data)
        return trans_data
    else:
        print("Error Code:", rescode)


import sys
import idaapi
import idc
import os
import idautils
import pprint
import struct
import binascii

myfunc=0
jump_table = dict()
switch_map = {}

text_seg = idaapi.get_segm_by_name('.text')
print('text segment base @ ', hex(text_seg.start_ea))

for func in idautils.Functions():
    if 'IumInvokeSecureService' == idc.get_func_name(func):
        print('function found')
        myfunc = func
        break

print(hex(myfunc))

for (startea, endea) in Chunks(myfunc):
    for head in Heads(startea, endea):
        switch_info = ida_nalt.get_switch_info(head)
        if (switch_info and switch_info.jumps != 0):
            num_cases = switch_info.get_jtable_size()
            print('good jump table found yeet')
            results = idaapi.calc_switch_cases(head, switch_info)
            for idx in range(results.cases.size()):
                cur_case = results.cases[idx]
                for cidx in range(len(cur_case)):
                    print("case: %d" % cur_case[cidx])
                    print("  goto 0x%x" % results.targets[idx])
                    try:
                        for insn in range(results.targets[idx], results.targets[idx+1]):
                            inst = idautils.DecodeInstruction(insn)
                            if not inst:
                                continue
                            if ida_idp.is_call_insn(inst) == True:
                                print(GetDisasm(insn))
                    except IndexError:
                        break
        else:
            continue


from PySide6.QtWidgets import (QWidget, QFrame, QGridLayout)

import CNbk
from CharFirstSymbFrame import CharFirstSymbFrame
from CharPercepFrame import CharPercepFrame
from CharStealthFrame import CharStealthFrame
from CharHiddenFrame import CharHiddenFrame
from CharUseCompetFrame import CharUseCompetFrame
from CharMelFrame import CharMelFrame
from CharThrFrame import CharThrFrame
from CharArmFrame import CharArmFrame
from CharPercFrame import CharPercFrame

class CharUsefulFrame(QWidget):
    """ Widget representing the character sheet summed up """

    def __init__(self):
        QWidget.__init__(self)
        self.grid = QGridLayout(self)

        self.CharFSymF = CharFirstSymbFrame()
        self.grid.addWidget(self.CharFSymF, 0, 0)

        self.CharPercepF = CharPercepFrame()
        self.grid.addWidget(self.CharPercepF, 1, 0)

        self.CharStealthF = CharStealthFrame()
        self.grid.addWidget(self.CharStealthF, 2, 0)

        self.CharHiddenF = CharHiddenFrame()
        self.grid.addWidget(self.CharHiddenF, 3, 0)

        self.CharUCompF = CharUseCompetFrame()
        self.grid.addWidget(self.CharUCompF, 4, 0)

        self.PercFrame = CharPercFrame()
        self.grid.addWidget(self.PercFrame, 5, 0, 2, 1)

        separator = QFrame(self)
        separator.setFrameShape(QFrame.VLine)
        separator.setLineWidth(3)
        self.grid.addWidget(separator, 0, 3, 9, 1)

        self.CharMelF = CharMelFrame()
        self.grid.addWidget(self.CharMelF, 0, 4, 2, 1)

        self.CharThrF = CharThrFrame()
        self.grid.addWidget(self.CharThrF, 2, 4, 2, 1)

        self.CharArmF = CharArmFrame()
        self.grid.addWidget(self.CharArmF, 4, 4, 3, 1)

    def get_selectedchar(self):
        """
        Method called to get the character selected to display

        :return: character (Perso_class.player)
        """
        return self.parent().get_selectedchar()

    def parent(self) -> CNbk.CharNotebook:
        """
        Method called to get the parent widget (the Notebook)

        :return: the reference to the parent
        """
        return self.parentWidget().parent()

    def refresh(self):
        """
        Method called to refresh all the statistics displayed in the widget

        :return: None
        """
        self.CharFSymF.refresh()
        self.CharPercepF.refresh()
        self.CharStealthF.refresh()
        self.CharHiddenF.refresh()
        self.CharUCompF.refresh()
        self.PercFrame.refresh()
        self.CharArmF.refresh()
        self.CharMelF.refresh()
        self.CharThrF.refresh()

    def save_character(self):
        """
        Method called to save the character

        :return: None
        """
        self.parent().save_character()


def balancedBracket(string):

    stack = []

    close_bracket = {
        ']': '[',
        '}': '{',
        ')': '('
    }

    allowed_brackets = [
        '[', ']',
        '(', ')',
        '{', '}'
    ]

    for item in string:

      if item not in allowed_brackets:
        continue

      if item not in close_bracket:
        stack.append(item)
      else:

        if len(stack) < 1:
          return False

        last = stack.pop()

        if last is not close_bracket[item]:
          return False

    if len(stack) > 0:
      return False

    return True

test_cases = {
    'test_case_1': {
        'description': 'normal test',
        'input': '[[[[[()]]]]]',
        'output': True,
        'active': True
    },
    'test_case_2': {
        'description': 'corrupt test',
        'input': '[[[[[(]]]]]',
        'output': False,
        'active': True
    },
    'test_case_3': {
        'description': 'letter test',
        'input': '(a)',
        'output': True,
        'active': True
    }
}

for test_name, data in test_cases.items():

    print('Running -> {} -> {}'.format(test_name, data['description']))

    if data['active'] == False:
      print('Skipped!')
      continue

    input = data['input']
    result = balancedBracket(input)
    if result == data['output']:
        print('Test passed!')
    else:
        print('Test fail')
        print('Expected Output: ', end="")
        print(data['output'])
        print('Actual Output: ', end="")
        print(result)
    print()


# 线程分为内核线程和用户线程
#   内核线程：由操作系统内核创建和撤销
#   用户线程：不需要内核支持而在用户程序中实现的线程

import threading
import time

exitFlag = 0

class myThread(threading.Thread):
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter

    def run(self):
        print("开始线程：" + self.name)
        print_time(self.name, self.counter, 5)
        print("退出线程：" + self.name)

def print_time(self, threadName, delay, counter):
    while counter:
        if exitFlag:
            threadName.exit()
        time.sleep(delay)
        print("%s : %s" % (threadName, time.ctime(time.time())))
        counter -= 1

thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(1, "Thread-2", 2)

thread1.start()
thread2.start()
thread1.join()
thread2.join()
print("退出主线程")

# 线程同步，Thread对象的Lock和Rlock可以实现简单的线程同步，这两个对象都有acquire和release方法
# 对于那些需要每次只允许一个线程操作的数据，可以将其操作放到acquire和release方法之间
# 当线程想要访问共享数据时，必须获得锁，否则需要等待其它线程释放锁，称为同步阻塞

class myThread (threading.Thread):
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter

    def run(self):
        print("开启线程：" + self.name)
        # 获取锁，用于线程同步
        threadLock.acquire()
        print_time(self.name, self.counter, 3)
        # 释放锁，开启下一个线程
        threadLock.release()

def print_time(threadName, delay, counter):
    while counter:
        time.sleep(delay)
        print("%s : %s" % (threadName, time.ctime(time.time())))
        counter -=1

threadLock = threading.Lock()
threads = []

# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

# 开启新线程
thread1.start()
thread2.start()

# 添加线程到线程列表
threads.append(thread1)
threads.append(thread2)

# 等待所有线程完成
for t in threads:
    t.join()
print("退出主线程")

# 线程优先级队列
# Python的 Queue模块中提供了同步的、线程安全的队列类

import queue
import threading
import time

exitFlag = 0

class myThread(threading.Thread):
    def __init__(self, threadID, name, q):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.q = q

    def run(self):
        print("开启线程：" + self.name)
        process_data(self.name, self.q)
        print("退出线程：" + self.name)

def process_data(threadName, q):
    while not exitFlag:
        queueLock.acquire()
        if not workQueue.empty():
            data = q.get()
            queueLock.release()
            print("%s processing %s" % (threadName, data))
        else:
            queueLock.release()
        time.sleep(1)

threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock()


#
#   This file part of our MPC controller for Level Control project
#
#   The Project is developed by Nagaraj Prakash, Prathamesh Kolekar and Srinidhi Subbanna
#   as part of our Case-Study for comparision of MPC and Override Control strategies.
#
#   This project is a free software: you can redistribute it and/or modify
#   it under the terms of the GNU Lesser General Public License as
#   published by the Free Software Foundation, either version 3
#   of the License, or (at your option) any later version.
#
#
#   You should have received a copy of the GNU General Public License
#   along with do-mpc.  If not, see <http://www.gnu.org/licenses/>.

import numpy as np
from casadi import *
from casadi.tools import *
import pdb
import sys
sys.path.append('../../')
import do_mpc

def template_mpc1(model1):
    """
    --------------------------------------------------------------------------
    template_mpc: tuning parameters
    --------------------------------------------------------------------------
    """
    mpc = do_mpc.controller.MPC(model1)

    setup_mpc = {
        'n_horizon': 20,
        'n_robust': 1,
        'open_loop': 0,
        't_step': 1,
        'state_discretization': 'collocation',
        'collocation_type': 'radau',
        'collocation_deg': 2,
        'collocation_ni': 2,
        'store_full_solution': True
        # Use MA27 linear solver in ipopt for faster calculations:
        #'nlpsol_opts': {'ipopt.linear_solver': 'MA27'}
    }

    mpc.set_param(**setup_mpc)

    #Setting Objective Function
    mterm = (((model1._x['L']) - 40)**2)
    lterm = (((model1._x['L']) - 40)**2)

    mpc.set_objective(mterm= mterm, lterm=lterm)
    mpc.set_rterm(F_out = 1) #Penalty function

    #setting bounds
    mpc.bounds['lower', '_x', 'L'] = 20.0
    mpc.bounds['upper', '_x', 'L'] = 80.0
    mpc.bounds['lower', '_u', 'F_out'] = 0.0
    mpc.bounds['upper', '_u', 'F_out'] = 50.0

    #Possible values for Uncertain value simulation
    mpc.set_uncertainty_values(F_in = np.array([1.0, 5.0, 10.0]))

    mpc.setup()

    return mpc


from __future__ import annotations

import os
from collections.abc import Iterable, Iterator, Mapping, Sequence
from copy import deepcopy
from pathlib import Path
from typing import Any
from unittest.mock import patch

import pytest
from attrs import frozen
from glom import T, assign, glom

from tests.cmd_util import invoke_build
from tests.fixture.config import get_basic_config
from tests.fixture.fsenv import FSEnv
from tests.fixture.time import TEST_TIME
from wap import __version__ as wap_version
from wap.exception import (
    ConfigError,
    EncodingError,
    PathExistsError,
    PathMissingError,
    PathTypeError,
    TagError,
)

INSTALLATION_ADDON_DIRS = {
    "mainline": "wow/_retail_/Interface/AddOns",
    "wrath": "wow/_classic_/Interface/AddOns",
    "vanilla": "wow/_classic_era_/Interface/AddOns",
}
SUFFIX_INTERFACE_PAIRS = [
    ("_Mainline", "90207"),
    ("_Vanilla", "11403"),
    ("_Wrath", "30400"),
    ("", "90207"),
]
PACKAGE_VERSION = get_basic_config()["version"]
PACKAGE_NAME = get_basic_config()["name"]

def check_basic_addon(addon_root: Path) -> None:
    config = get_basic_config()
    expected_toc_files = ["Main.lua", "Extra.lua"]
    expected_toc_tags = {
        "Title": glom(config, "package.0.toc.tags.Title"),
        "Version": PACKAGE_VERSION,
        # first consult tag Author, then top-level author key
        "Author": (
            glom(config, "package.0.toc.tags.Author", default=None)
            or glom(config, "author", default=None)
        ),
        "Notes": glom(config, "package.0.toc.tags.Notes"),
        "X-BuildDateTime": str(TEST_TIME),
        "X-BuildTool": f"wap {wap_version}",
    }
    for suffix, interface in SUFFIX_INTERFACE_PAIRS:
        path = addon_root / f"{addon_root.name}{suffix}.toc"
        toc = Toc.parse(path)
        assert toc == Toc(
            tags={k: v for k, v in expected_toc_tags.items() if v is not None}
            | {"Interface": interface},
            files=expected_toc_files,
        )

    expected_files = {
        addon_root / "Main.lua",
        addon_root / "Extra.lua",
        addon_root / "LICENSE",
    }
    for expected_file in expected_files:
        assert expected_file.is_file()

@frozen(kw_only=True)
class Toc:
    """
    Rudimentary recreation of toc parsing. just good enough for testing. dont want
    to use the SOT's code to do this.
    """

    tags: Mapping[str, str]
    files: Sequence[str]

    @classmethod
    def parse(cls, path: Path) -> Toc:
        contents = path.read_text()
        tags = {}
        files = []
        for line in contents.splitlines():
            if line.startswith("##"):
                key, _, value = line.removeprefix("##").partition(":")
                tags[key.strip()] = value.strip()
            elif not line.startswith("#") and line:
                files.append(line.strip())

        return Toc(tags=tags, files=files)

def test_build_normal(fs_env: FSEnv) -> None:
    config = get_basic_config()
    config["package"].append(deepcopy(config["package"][0]))
    assign(config, "package.1.path", "./Addon2")
    fs_env.write_config(config)

    fs_env.place_addon("basic")
    fs_env.place_addon("basic", "Addon2")
    fs_env.place_file("LICENSE")

    result = invoke_build()

    assert result.success

    check_basic_addon(Path(f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon"))
    check_basic_addon(Path(f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon2"))

def test_build_dupe_addon_path(fs_env: FSEnv) -> None:
    config = get_basic_config()
    config["package"].append(config["package"][0])
    fs_env.write_config(config)

    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    result = invoke_build()

    assert isinstance(result.exception, ConfigError)

def test_build_different_output_path(fs_env: FSEnv) -> None:
    fs_env.write_config(get_basic_config())
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    output_path = "output"

    result = invoke_build(["--output-path", output_path])

    assert result.success

    check_basic_addon(Path(f"{output_path}/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon"))

def test_build_different_config_path(fs_env: FSEnv) -> None:
    config_path = "config.json"
    fs_env.write_config(get_basic_config(), config_path)
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    result = invoke_build(["--config-path", config_path])

    assert result.success

    check_basic_addon(Path(f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon"))

def test_build_config_discovery(fs_env: FSEnv) -> None:
    fs_env.write_config(get_basic_config())
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    os.chdir(Path("Addon"))

    result = invoke_build()

    assert result.success

    check_basic_addon(Path(f"../dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon"))

def test_build_config_discovery_fail(fs_env: FSEnv) -> None:
    result = invoke_build()

    assert isinstance(result.exception, SystemExit)

@pytest.mark.parametrize("top_level_author", [True, False])
@pytest.mark.parametrize("toc_author", [True, False])
def test_build_author_fallback(
    fs_env: FSEnv, top_level_author: bool, toc_author: bool
) -> None:
    config = get_basic_config()

    top_level_author_name = "top-level"
    toc_author_name = "toc"
    if top_level_author:
        assign(config, "author", top_level_author_name)
    if toc_author:
        assign(config, "author", toc_author_name)

    fs_env.write_config(get_basic_config())
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    result = invoke_build()

    assert result.success

    check_basic_addon(Path(f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon"))

def test_build_missing_config() -> None:
    result = invoke_build()

    # i wish a more descriptive exception was thrown than SystemExit, but we have no
    # choice because click controls this raise
    assert isinstance(result.exception, SystemExit)

def test_build_config_is_not_file(fs_env: FSEnv) -> None:
    fs_env.place_dir("wap.json")

    result = invoke_build()

    assert isinstance(result.exception, SystemExit)

def test_build_missing_addon(fs_env: FSEnv) -> None:
    fs_env.write_config(get_basic_config())
    fs_env.place_file("LICENSE")

    result = invoke_build()

    assert isinstance(result.exception, PathTypeError)

def test_build_addon_path_is_not_dir(fs_env: FSEnv) -> None:
    fs_env.write_config(get_basic_config())
    fs_env.place_file("Addon")
    fs_env.place_file("LICENSE")

    result = invoke_build()

    assert isinstance(result.exception, PathTypeError)

@pytest.mark.parametrize(
    "link_arg",
    [
        "mainline",
        "wrath",
        "vanilla",
    ],
)
def test_build_with_linking(fs_env: FSEnv, link_arg: str) -> None:
    fs_env.write_config(get_basic_config())
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    args: list[str] = []
    for flavor, path in INSTALLATION_ADDON_DIRS.items():
        args.extend((f"--{flavor}-addons-path", path))
        fs_env.place_dir(path, parents=True, exist_ok=True)

    args.extend(["--link", link_arg])

    result = invoke_build(args)

    assert result.success
    assert (
        Path(f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon").resolve()
        == (Path(INSTALLATION_ADDON_DIRS[link_arg]) / "Addon").resolve()
    )
    assert "Linked" in result.stderr

@pytest.mark.parametrize(
    "link_arg",
    [
        "mainline",
        "wrath",
        "vanilla",
    ],
)
def test_build_link_already_linked(fs_env: FSEnv, link_arg: str) -> None:
    fs_env.write_config(get_basic_config())
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    args: list[str] = []
    for flavor, path in INSTALLATION_ADDON_DIRS.items():
        args.extend((f"--{flavor}-addons-path", path))
        fs_env.place_dir(path, parents=True, exist_ok=True)

    # create initial fake output dir so that linking works
    build_dir = fs_env.place_dir(
        f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon", parents=True
    )
    (Path(INSTALLATION_ADDON_DIRS[link_arg]) / "Addon").symlink_to(
        build_dir, target_is_directory=True
    )

    args.extend(["--link", link_arg])

    result = invoke_build(args)

    assert result.success
    assert (
        Path(f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon").resolve()
        == (Path(INSTALLATION_ADDON_DIRS[link_arg]) / "Addon").resolve()
    )

@pytest.mark.parametrize(
    "link_arg",
    [
        "mainline",
        "wrath",
        "vanilla",
    ],
)
def test_build_link_path_exists(fs_env: FSEnv, link_arg: str) -> None:
    fs_env.write_config(get_basic_config())
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    args: list[str] = []
    for flavor, path in INSTALLATION_ADDON_DIRS.items():
        args.extend((f"--{flavor}-addons-path", path))
        fs_env.place_dir(path, parents=True, exist_ok=True)

    # create a dir in the spot where the link would be made
    fs_env.place_dir(str(Path(INSTALLATION_ADDON_DIRS[link_arg]) / "Addon"))

    args.extend(["--link", link_arg])

    result = invoke_build(args)

    assert isinstance(result.exception, PathExistsError)

@pytest.mark.parametrize(
    "link_arg",
    [
        "mainline",
        "wrath",
        "vanilla",
    ],
)
def test_build_link_path_exists_force(fs_env: FSEnv, link_arg: str) -> None:
    fs_env.write_config(get_basic_config())
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    args: list[str] = []
    for flavor, path in INSTALLATION_ADDON_DIRS.items():
        args.extend((f"--{flavor}-addons-path", path))
        fs_env.place_dir(path, parents=True, exist_ok=True)

    # create a dir in the spot where the link would be made
    fs_env.place_dir(str(Path(INSTALLATION_ADDON_DIRS[link_arg]) / "Addon"))

    args.extend(["--link", link_arg, "--link-force"])

    result = invoke_build(args)

    assert result.success
    assert (
        Path(f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon").resolve()
        == (Path(INSTALLATION_ADDON_DIRS[link_arg]) / "Addon").resolve()
    )

@pytest.mark.parametrize("add_auto", [True, False])
@pytest.mark.parametrize(
    "exist_flavor",
    [
        "mainline",
        "wrath",
        "vanilla",
    ],
)
def test_build_with_auto_linking(
    fs_env: FSEnv, add_auto: bool, exist_flavor: str
) -> None:
    fs_env.write_config(get_basic_config())
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    args: list[str] = []
    for flavor, path in INSTALLATION_ADDON_DIRS.items():
        args.extend((f"--{flavor}-addons-path", path))
        if exist_flavor == flavor:
            fs_env.place_dir(path, parents=True, exist_ok=True)

    args.append("--link")
    if add_auto:
        args.append("auto")

    result = invoke_build(args)

    assert result.success
    assert (
        Path(f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon").resolve()
        == (Path(INSTALLATION_ADDON_DIRS[exist_flavor]) / "Addon").resolve()
    )
    for flavor, path in INSTALLATION_ADDON_DIRS.items():
        if exist_flavor != flavor:
            assert not (Path(path) / "Addon").exists()

@pytest.mark.parametrize(
    "other_flavor",
    [
        "mainline",
        "wrath",
        "vanilla",
    ],
)
def test_build_link_auto_and_other(fs_env: FSEnv, other_flavor: str) -> None:
    fs_env.write_config(get_basic_config())
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    result = invoke_build(["--link", "auto", "--link", other_flavor])

    assert isinstance(result.exception, SystemExit)

def test_build_non_unicode_config(fs_env: FSEnv) -> None:
    config_path = fs_env.write_config(get_basic_config())
    config_path.write_text(
        config_path.read_text().replace("Package", "包裹"), encoding="big5"
    )
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    result = invoke_build()

    assert isinstance(result.exception, EncodingError)

def test_build_overwriting_src_include(fs_env: FSEnv) -> None:
    fs_env.write_config(assign(get_basic_config(), "package.0.include", ["./Main.lua"]))
    fs_env.place_addon("basic")
    fs_env.place_file("Main.lua")

    result = invoke_build()

    assert result.success
    assert "already exists" in result.stderr

def test_build_overwriting_toc_include(fs_env: FSEnv) -> None:
    fs_env.write_config(
        assign(get_basic_config(), "package.0.include", ["./Addon.toc"])
    )
    fs_env.place_addon("basic")
    fs_env.place_file("Addon.toc")

    result = invoke_build()

    assert result.success
    assert "already exists" in result.stderr

def test_build_addon_dir_exists_as_file(fs_env: FSEnv) -> None:
    fs_env.write_config(get_basic_config())
    fs_env.place_addon("basic")
    fs_env.place_file(f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon", parents=True)

    result = invoke_build()

    assert isinstance(result.exception, PathExistsError)

@pytest.mark.parametrize(
    "clean",
    [
        True,
        False,
    ],
)
def test_build_cleaning(fs_env: FSEnv, clean: bool) -> None:
    fs_env.write_config(get_basic_config())
    fs_env.place_addon("basic")
    old = fs_env.place_file(
        f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon/old", parents=True
    )

    args = ["--clean"] if clean else []
    result = invoke_build(args)

    assert result.success
    assert old.exists() != clean

def test_build_include_missing(fs_env: FSEnv) -> None:
    fs_env.write_config(get_basic_config())
    fs_env.place_addon("basic")

    result = invoke_build()

    assert result.success
    assert "none were found" in result.stderr

def test_build_include_dir(fs_env: FSEnv) -> None:
    fs_env.write_config(
        assign(get_basic_config(), "package.0.include", ["./a-directory"])
    )
    fs_env.place_addon("basic")
    fs_env.place_dir("a-directory")

    result = invoke_build()

    assert result.success
    assert Path(f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon/a-directory").is_dir()

def test_build_toc_file_missing(fs_env: FSEnv) -> None:
    config = get_basic_config()
    glom(config, ("package.0.toc.files", T.append("NotExist.lua")))
    fs_env.write_config(config)
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    result = invoke_build()

    assert isinstance(result.exception, PathMissingError)

@pytest.mark.parametrize(
    "toc_suffix",
    [
        "",
        "_Wrath",
        "_Vanilla",
    ],
)
def test_build_gen_toc_overwrites(fs_env: FSEnv, toc_suffix: str) -> None:
    fs_env.write_config(get_basic_config())
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    fs_env.place_file(f"Addon/Addon{toc_suffix}.toc")

    result = invoke_build()

    assert result.success
    assert "already exists" in result.stderr

def test_build_include_dir_overwrite_file(fs_env: FSEnv) -> None:
    fs_env.write_config(
        assign(get_basic_config(), "package.0.include", ["./a", "./b/a"])
    )
    fs_env.place_addon("basic")
    fs_env.place_file("a")
    fs_env.place_dir("b/a", parents=True)

    result = invoke_build()

    assert isinstance(result.exception, PathExistsError)

def test_build_include_file_overwrite_file(fs_env: FSEnv) -> None:
    fs_env.write_config(
        assign(get_basic_config(), "package.0.include", ["./a", "./b/a"])
    )
    fs_env.place_addon("basic")
    fs_env.place_file("a", text="first")
    fs_env.place_file("b/a", parents=True, text="last")

    result = invoke_build()

    assert result.success
    assert Path(f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon/a").read_text() == "last"

def test_build_include_dir_overwrite_dir(fs_env: FSEnv) -> None:
    fs_env.write_config(
        assign(get_basic_config(), "package.0.include", ["./a", "./b/a"])
    )
    fs_env.place_addon("basic")
    fs_env.place_dir("a")
    fs_env.place_dir("b/a", parents=True)

    result = invoke_build()

    assert result.success
    assert Path(f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon/a").is_dir()

def test_build_include_file_overwrite_dir(fs_env: FSEnv) -> None:
    fs_env.write_config(
        assign(get_basic_config(), "package.0.include", ["./a", "./b/a"])
    )
    fs_env.place_addon("basic")
    fs_env.place_dir("a")
    fs_env.place_file("b/a", parents=True)

    result = invoke_build()

    assert isinstance(result.exception, PathExistsError)

def test_build_toc_included(fs_env: FSEnv) -> None:
    fs_env.write_config(
        assign(get_basic_config(), "package.0.include", ["./Addon.toc"])
    )
    fs_env.place_addon("basic")
    fs_env.place_dir("Addon.toc")

    result = invoke_build()

    assert isinstance(result.exception, PathExistsError)

@pytest.mark.parametrize("load_on_demand,expected", [(True, "1"), (False, "0")])
def test_build_toc_load_on_demand(
    fs_env: FSEnv, load_on_demand: bool, expected: str
) -> None:
    fs_env.write_config(
        assign(get_basic_config(), "package.0.toc.tags.LoadOnDemand", load_on_demand)
    )
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    result = invoke_build()

    assert result.success

    for suffix, _ in SUFFIX_INTERFACE_PAIRS:
        toc_path = Path(
            f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon/Addon{suffix}.toc"
        )
        toc = Toc.parse(toc_path)
        assert {("LoadOnDemand", expected)} <= toc.tags.items()

@pytest.mark.parametrize(
    "default_state,expected", [(True, "enabled"), (False, "disabled")]
)
def test_build_toc_default_state(
    fs_env: FSEnv, default_state: bool, expected: str
) -> None:
    fs_env.write_config(
        assign(get_basic_config(), "package.0.toc.tags.DefaultState", default_state)
    )
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    result = invoke_build()

    assert result.success

    for suffix, _ in SUFFIX_INTERFACE_PAIRS:
        toc_path = Path(
            f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon/Addon{suffix}.toc"
        )
        toc = Toc.parse(toc_path)
        assert {("DefaultState", expected)} <= toc.tags.items()

@pytest.mark.parametrize(
    "tag_name",
    [
        "Dependencies",
        "OptionalDeps",
        "LoadWith",
        "LoadManagers",
        "SavedVariables",
        "SavedVariablesPerCharacter",
    ],
)
@pytest.mark.parametrize(
    "tag_value,expected", [([], ""), (["a"], "a"), (["a", "b", "c"], "a, b, c")]
)
def test_build_toc_list_type_tags(
    fs_env: FSEnv, tag_name: str, tag_value: list[str], expected: str
) -> None:
    fs_env.write_config(
        assign(get_basic_config(), f"package.0.toc.tags.{tag_name}", tag_value)
    )
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    result = invoke_build()

    assert result.success

    for suffix, _ in SUFFIX_INTERFACE_PAIRS:
        toc_path = Path(
            f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon/Addon{suffix}.toc"
        )
        toc = Toc.parse(toc_path)
        assert {(tag_name, expected)} <= toc.tags.items()

@pytest.mark.parametrize("bad_tag", ["foo bar", "foo\nbar", "foo:bar"])
def test_build_toc_bad_tags(fs_env: FSEnv, bad_tag: str) -> None:
    config = get_basic_config()
    config["package"][0]["toc"]["tags"][bad_tag] = "value"
    fs_env.write_config(config)
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    result = invoke_build()

    assert isinstance(result.exception, TagError)

def test_build_watch_edit_source_file(fs_env: FSEnv) -> None:
    fs_env.write_config(get_basic_config())
    addon_path = fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    changing_file_path = addon_path / "Main.lua"
    original_text = "original"
    new_text = "updated"
    assert original_text != new_text

    changing_file_path.write_text(original_text)

    def edit_file(*args: Any, **kwargs: Any) -> Iterator[Iterable[Path]]:
        changing_file_path.write_text(new_text)
        yield {changing_file_path.resolve()}

    with patch("tests.cmd_util.build.watch_paths", side_effect=edit_file):
        result = invoke_build(["--watch"])

    assert result.success

    new_output_file_path = Path(f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon/Main.lua")
    assert new_output_file_path.read_text() == new_text

def test_build_watch_new_source_file(fs_env: FSEnv) -> None:
    fs_env.write_config(get_basic_config())
    addon_path = fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    # create a new file in a directory
    new_file_path = addon_path / "Dir" / "New.lua"
    new_text = "new"

    def create_file(*args: Any, **kwargs: Any) -> Iterator[Iterable[Path]]:
        new_file_path.parent.mkdir()
        new_file_path.write_text(new_text)
        yield {new_file_path.resolve()}

    with patch("tests.cmd_util.build.watch_paths", side_effect=create_file):
        result = invoke_build(["--watch"])

    assert result.success

    new_output_file_path = Path(
        f"dist/{PACKAGE_NAME}-{PACKAGE_VERSION}/Addon/Dir/New.lua"
    )
    assert new_output_file_path.read_text() == new_text

def test_build_watch_config_file(fs_env: FSEnv) -> None:
    config = get_basic_config()
    fs_env.write_config(config)
    fs_env.place_addon("basic")
    fs_env.place_file("LICENSE")

    new_version = "9.9.9"
    new_text = "new"
    fs_env.place_file("New.txt", text=new_text)

    def edit_config(*args: Any, **kwargs: Any) -> Iterator[Iterable[Path]]:
        # do two arbitrary things that we can later test:
        # 1. add another include (so it will show up in the output dir)
        # 2. change the package version (so the output dir path changes)
        config["package"][0]["include"].append("./New.txt")
        config["version"] = new_version
        config_path = fs_env.write_config(config)
        yield {config_path.resolve()}

    with patch("tests.cmd_util.build.watch_paths", side_effect=edit_config):
        result = invoke_build(["--watch"])

    assert result.success

    assert (
        Path(f"dist/{PACKAGE_NAME}-{new_version}/Addon/New.txt").read_text() == new_text
    )


import os
import config
from flask import Flask
from models.base_model import db
from flask_wtf.csrf import CSRFProtect
from flask_login import LoginManager
import urllib

web_dir = os.path.join(os.path.dirname(
    os.path.abspath(__file__)), 'rentista_web')

app = Flask('Rentista', root_path=web_dir)
csrf = CSRFProtect(app)

if os.getenv('FLASK_ENV') == 'production':
    app.config.from_object("config.ProductionConfig")
else:
    app.config.from_object("config.DevelopmentConfig")

login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = "sessions.new"

@app.template_filter('clean_querystring')
def clean_querystring(request_args, *keys_to_remove, **new_values):
    # We'll use this template filter in the pagination include. This filter
    # will take the current URL and allow us to preserve the arguments in the
    # querystring while replacing any that we need to overwrite. For instance
    # if your URL is /?q=search+query&page=2 and we want to preserve the searchx
    # term but make a link to page 3, this filter will allow us to do that.
    querystring = dict((key, value) for key, value in request_args.items())
    for key in keys_to_remove:
        querystring.pop(key, None)
    querystring.update(new_values)
    return urllib.parse.urlencode(querystring)

@app.before_request
def before_request():
    db.connect()

@app.teardown_request
def _db_close(exc):
    if not db.is_closed():
        print(db)
        print(db.close())
    return exc

@login_manager.user_loader
def load_user(user_id):
    from models.user import User
    return User.get_by_id(user_id)


"""
List Functions

You are working on a queue management program.
The queue is represented by a list.
Write a program to take an input, add it to the end of the queue, and output the resulting list.
"""
queue = ['John', 'Amy', 'Bob', 'Adam']  #  crea una list
x= input()   #  guarda una entrada en una variable
queue.insert(x)  #  inserta en la list la varibale
print(queue)  #  impreme las list


# 전역변수와 지역변수

def DFS1():
  cnt=3
  print(cnt)

def DFS2():
  global cnt # global 전역변수
  if cnt == 5:
    print(cnt)

if __name__ == "__main__": # 메인함수 선언, 시작을 의미 해당코드 밑에 main등의 함수를 작성하여 호출
  cnt=5 # 전역변수는 모든 함수가 접근가능
  DFS1()
  DFS2()
  print(cnt)

# 파이썬에서 __name__ 변수는 내부적으로 사용되는 특별한 변수 이름입니다.
# 위의 예제에서 python taeng.py와 같이 직접 taeng.py 파일을 실행하는 경우에는
# __name___ 변수에 __main__ 이라는 값이 할당됩니다.

# 다만 마지막에서 살펴본 모듈 불러오기와 같이 import taengModule을 통해서 모듈을 불러와서 사용하는 경우
# __name__ 변수에는 모듈 이름(여기서는 taengModule)이 저장됩니다.

# 결론적으로 if __name__ == "__main__"와 같이 조건문을 사용하여
# 터미널에서와 같이 직접 호출되어 사용될 때는
# 그 자체로 기능을 수행하고,
# 동시에 다른 모듈에서 필요한 함수 등을 제공할 수 있습니다.


from django.shortcuts import render, redirect, get_object_or_404
from pytz import timezone
from .models import Participantes
# Create your views here.

def home(request):
    return render(request, "index.html")

def agregarParticipantes(request):
    codigo=request.POST['txtCodigo']
    nombre=request.POST['txtNombre']
    correo=request.POST['txtCorreo']
    celular=request.POST['txtCelular']
    #fecha_actualizado=request.POST['txtFecha_a']
    #participantes = Participantes.objects.create(
    #codigo=codigo, nombre=nombre, correo=correo, celular=celular)
    codigo = Participantes.objects.get(codigo=codigo)
    #codigo = get_object_or_404(Participantes, codigo=codigo)

    codigo.nombre = nombre
    codigo.correo = correo
    codigo.celular = celular
    #codigo.fecha_actualizado = datetime.now()
    codigo.save()

    return render(request, "index.html")


import pandas as pd
import copy
from collections import deque
import random
import json
import numpy as np
from copy import copy
import math

from property_selector import PropertySelector
from property_selector import SetPropertySelector

sets = pd.read_csv('set_inputs.txt', delimiter='\t')
weapons = pd.read_csv('weapons.txt', delimiter='\t')
armor = pd.read_csv('armor.txt', delimiter='\t')
jewelry = pd.read_csv('jewelry.txt', delimiter='\t')

weapons = weapons.query('spawnable == 1')
weapons = weapons.query('type != "tpot"')

armor = armor.query('spawnable == 1')
jewelry = jewelry.query('spawnable == 1')

weapons['itemclass'] = 'weap'
armor['itemclass'] = 'armo'

# Load template file
with open('itemtemplate.json', 'r') as tfile:
    itemtemplate = json.load(tfile)
with open('settemplate.json', 'r') as tfile:
    settemplate = json.load(tfile)

def fetch_random_item(type_exclusions, type_restrictions = [], minlvl = 0, handsAvail = 2, allowHybrid = False):
    if handsAvail <= 0:
        type_exclusions.append('shie')
        df = pd.concat([armor, jewelry])
    else:
        w = weapons
        if len(type_restrictions) > 0:
            w = w.query(f'type in @type_restrictions')

        if handsAvail == 1 and allowHybrid:
            w = w[(w['2handed'] != 1) | (w['1or2handed'] == 1)]
        elif handsAvail == 1 and ~allowHybrid:
            w = pd.DataFrame()

        df = pd.concat([w, armor, jewelry])

    if minlvl > 0:
        df = df.query(f'level > {minlvl-6} and level <= {minlvl+6}')
    if len(type_exclusions) > 0:
        df = df.query(f'type not in @type_exclusions')

    sample = df.sample()
    return sample

def update_exclusion_types(exclusion_list, itemtype):
    exclusion_list.append(itemtype)
    if itemtype == 'helm':
        exclusion_list.append('circ')
    elif itemtype == 'circ':
        exclusion_list.append('helm')

num_items = np.random.normal(4, 2, sets.shape[0])
sets['NumberOfItems'] = num_items.astype(int)
sets['NumberOfItems'] = np.minimum(6, sets['NumberOfItems'])
sets['NumberOfItems'] = np.maximum(2, sets['NumberOfItems'])

sets = list(sets.values)
q = deque(sets)

idx = 1250

type_exclusions_by_class = {
    'ama' : ['wand', 'scep', 'knif', 'swor', 'axe', 'mace', 'club', 'hamm', 'tkni', 'taxe', 'staf', 'h2h', 'h2h2', 'orb', 'pelt', 'phlm', 'ashd', 'head'],
    'bar' : ['wand', 'scep', 'knif', 'staf', 'h2h', 'h2h2', 'orb', 'pelt', 'ashd', 'ajav', 'aspe', 'abow', 'head', 'bow', 'xbow'],
    'sor' : ['h2h', 'h2h2', 'pelt', 'ashd', 'ajav', 'aspe', 'abow', 'tkni', 'taxe', 'head','bow', 'xbow', 'jave', 'phlm'],
    'dru' : ['wand', 'scep', 'knif', 'tkni', 'taxe', 'staf', 'h2h', 'h2h2', 'orb', 'phlm', 'ashd', 'ajav', 'aspe', 'abow', 'head','bow', 'xbow', 'jave'],
    'ass' : ['wand', 'scep', 'knif', 'swor', 'axe', 'club', 'hamm', 'tkni', 'taxe', 'staf', 'orb', 'pelt', 'phlm', 'ashd', 'ajav', 'aspe', 'abow', 'head','bow', 'xbow', 'jave'],
    'nec' : ['scep', 'tkni', 'taxe', 'staf', 'h2h', 'h2h2', 'orb', 'pelt', 'phlm', 'ashd', 'ajav', 'aspe', 'abow','bow', 'xbow', 'jave'],
    'pal' : ['wand', 'knif', 'tkni', 'taxe', 'staf', 'h2h', 'h2h2', 'orb', 'pelt', 'phlm', 'ajav', 'aspe', 'abow', 'head', 'bow', 'xbow', 'jave']
}

# "[Class Skill Tab ID] = (Amazon = 0-2, Sorceress = 3-5, Necromancer = 6-8, Paladin = 9-11, Barbarian = 12-14, Druid = 15-17,  Assassin = 18-20)"
skilltablookup = {
    'ama' : {
        34 : 0,
        35 : 0,
        25 : 0,
        15 : 0,
        24 : 0,
        32 : 1,
        31 : 2,
        21 : 2,
        11 : 2,
        12 : 2,
        22 : 2,
        26 : 2,
        7 : 2,
        16 : 2,
        27 : 2
    },
    'ass' : {
        274 : 18,
        275 : 18,
        278 : 19,
        279 : 19,
        271 : 20,
        277 : 20,
    },
    'bar' : {
        148 : 13,
        145 : 13,
        153 : 13,
        151 : 14,
        147 : 14
    },
    'dru' : {
        250 : 15,
        225 : 15,
        229 : 15,
        249 : 15,
        248 : 16,
        238 : 16,
        233 : 16,
        247 : 17
    },
    'nec' : {
        75 : 6,
        85 : 6,
        94 : 6,
        90 : 6,
        84 : 7,
        93 : 7,
        92 : 7,
        73 : 7
    },
    'pal' : {
        122 : 10,
        103 : 10,
        119 : 10,
        118 : 10,
        114 : 10,
        102 : 10,
        106 : 11,
        121 : 11
    },
    'sor' : {
        59 : 3,
        64 : 3,
        57 : 4,
        48 : 4,
        53 : 4,
        62 : 5,
        51 : 5,
        56 : 5,
        52 : 5
    }
}
itemcache = set()

def getNameComponents():
    newnames = pd.read_csv('names.txt', delimiter = '\t', header=None)
    newnames = set(newnames[0].values)
    components = set()
    for n in newnames:
        parts = n.split(' ')
        components = components.union(set(parts))

    first = []
    second = []
    for k in components:
        if k in ['of', 'the']:
            continue
        first.append(k)
        if '\'' not in k and 'ing' not in k:
            second.append(k)
    return first, second

def generateItemName(first, second):
    global itemcache
    f, s = random.sample(first, 1)[0], random.sample(second, 1)[0]
    newname = ' '.join([f, s])
    if newname in itemcache:
        return generateItemName(first, second)
    else:
        itemcache.add(newname)
        return newname

setNames = set()
def create_items(firstNames, secondNames):
    global idx
    setItems = []
    sets = []
    propertySelector = PropertySelector(affix_file = 'set_item_affixes.txt')
    setPropertySelector = SetPropertySelector(affix_file = 'set_bonus_affixes.txt')

    # For each set...
    while q:
        skill, id, charclass, element, minilvl, type_restrictions, numitems = q.popleft()

        # Randomly uplevel the set
        level = random.randint(minilvl, 80)

        # Get Set Name
        setName = generateItemName(firstNames, secondNames)
        firstName = setName.split(' ')[0:1]
        firstNames.remove(firstName[0])
        print(skill, id, charclass, element, minilvl, level, numitems, firstName[0])

        setObject = copy(settemplate)
        setObject['index'] = setName
        setObject['name'] = setName

        exclusion_list = copy(type_exclusions_by_class[charclass])
        restriction_list = type_restrictions.split(',') if type(type_restrictions) == type('') else []

        items = []
        rings = 0
        hands = 2
        auraSet = False
        oskillSet = False
        exclusion_list.append('shie')

        # For each item ...
        while len(items) < numitems:
            item = fetch_random_item(exclusion_list, type_restrictions = restriction_list, minlvl = level, handsAvail = hands, allowHybrid = True if charclass == 'bar' else False)
            item['level'] = level

            itemtype = item['type'].values[0]
            itemclass = item['itemclass'].values[0]

            if itemtype == 'shie':
                hands -= 1
                update_exclusion_types(exclusion_list, itemtype)
            elif itemclass == 'weap':
                hands -= 1
                if item['2handed'].values[0] == 1:
                    hands -= 1

                if item['1or2handed'].values[0] == 1 and charclass == 'bar':
                    hands += 1

                if hands == 1:
                    exclusion_list.remove('shie')
            elif itemtype == 'ring':
                rings += 1
                if rings >= 2:
                    exclusion_list.append(itemtype)
            else:
                update_exclusion_types(exclusion_list, itemtype)

            # Sanitize level 0 -> level 1
            level = max(level, 1)
            # Sanitize level > 100 -> level 99
            level = min(level, 99)

            propertyCodes = []

            if auraSet:
                propertyCodes.append('aura')
            if oskillSet:
                propertyCodes.append('oskill')

            # Number of properties
            minprop, maxprop = int(np.log(level) * 1), int(np.log(level) * 1.5)
            minprop, maxprop = max(minprop, 2), max(min(maxprop, 6), 3)
            numprop = random.randint(minprop, maxprop)

            # Select elemental type
            etype = element

            outitem = copy(itemtemplate)
            outitem['index'] = generateItemName(firstName, secondNames)
            outitem['*ID'] = idx+407
            outitem['set'] = setName
            outitem['lvl'] = int(level)
            outitem['item'] = item['code'].values[0]
            outitem['add func'] = 2
            outitem['*ItemName'] = item['name'].values[0]

            c = 0
            hlevel = 1
            # For each property
            while c < numprop:
                prop = propertySelector.search_property(level, itemclass, itemtype, etype, hlevel, propertyCodes, forceClass = charclass)
                propertyCodes.append(prop['Property'].values[0])

                if prop['Property'].values[0] == 'aura':
                    auraSet = True
                elif prop['Property'].values[0] == 'oskill':
                    oskillSet = True

                if hlevel == 1:
                    hlevel = random.randint(1, 2)
                elif hlevel == 2:
                    hlevel = random.sample([2, 2, 3], 1)[0]
                elif hlevel == 3:
                    hlevel = random.sample([3, 3, 3, 1], 1)[0]

                param = prop['Param'].values[0]
                if type(param) == type('str') and param.isnumeric() == False:
                    param = random.sample(param.split(','), 1)[0]
                    param = param.strip()

                func = prop['LvlFunc'].values[0]
                minval = prop['MinValue'].values[0]
                maxval = prop['MaxValue'].values[0]

                try:
                    if func != '':

                        if func == 'linear':
                            minval = str(minval).replace('x', str(level))
                            maxval = str(maxval).replace('x', str(level))
                            minval, maxval = math.floor(eval(minval)), math.ceil(eval(maxval))
                        elif func == 'ln':
                            x = np.log(level)

                            minval = str(minval).replace('x', str(x))
                            maxval = str(maxval).replace('x', str(x))
                            minval, maxval = math.floor(eval(minval)), math.ceil(eval(maxval))

                        minval, maxval = float(minval), float(maxval)
                except SyntaxError:
                    print('ERROR')
                    print(prop, func, minval, maxval)
                    raise
                except ValueError:
                    print('ERROR')
                    print(prop, func, minval, maxval)
                    raise

                maxval = max(maxval, minval)
                outitem[f'prop{c+1}'] = prop['Property'].values[0]
                outitem[f'par{c+1}'] = '' if pd.isna(param) else param
                outitem[f'min{c+1}'] = int(minval)
                outitem[f'max{c+1}'] = int(maxval)

                c += 1

            anumprop = random.randint(math.floor(numitems/2), min(5, numitems-1))

            apropertyCodes = []
            propertyType = 'ascaler'

            c = 0
            # For each aproperty itype, etype, prop_type, used_prop_codes,
            while c < anumprop:
                prop = setPropertySelector.search_property(itemclass, element, propertyType, apropertyCodes, forceClass = charclass)
                propcode = prop['prop'].values[0]
                apropertyCodes.append(propcode)

                param = prop['param'].values[0]
                if type(param) == type('str') and param.isnumeric() == False:
                    param = random.sample(param.split(','), 1)[0]

                func = prop['LvlFunc'].values[0]
                minval = prop['MinValue'].values[0]
                maxval = prop['MaxValue'].values[0]

                try:
                    if func != '':

                        if func == 'linear':
                            minval = str(minval).replace('x', str(level))
                            maxval = str(maxval).replace('x', str(level))
                            minval, maxval = math.floor(eval(minval)), math.ceil(eval(maxval))
                        elif func == 'ln':
                            x = np.log(level)

                            minval = str(minval).replace('x', str(x))
                            maxval = str(maxval).replace('x', str(x))
                            minval, maxval = math.floor(eval(minval)), math.ceil(eval(maxval))

                        minval, maxval = float(minval), float(maxval)
                except SyntaxError:
                    print('ERROR')
                    print(prop, func, minval, maxval)
                    raise
                except ValueError:
                    print('ERROR')
                    print(prop, func, minval, maxval)
                    raise

                if propcode == 'skill':
                    param = id
                elif propcode == 'skilltab':
                    param = skilltablookup[charclass][id]

                maxval = max(maxval, minval)
                outitem[f'aprop{c+1}a'] = propcode
                outitem[f'apar{c+1}a'] = '' if pd.isna(param) else param
                outitem[f'amin{c+1}a'] = int(minval)
                outitem[f'amax{c+1}a'] = int(maxval)

                c += 1

            idx += 1
            items.append(outitem)
            setItems.append(outitem)

        # Build partial set props
        pnumprops = random.randint(2, max(2, min(4,numitems-1)))

        ppropertyCodes = []
        propertyType = 'pscaler'

        c = 0
        while c < pnumprops:
            prop = setPropertySelector.search_property('all', element, propertyType, ppropertyCodes, forceClass = charclass)
            propcode = prop['prop'].values[0]
            ppropertyCodes.append(propcode)

            param = prop['param'].values[0]
            if type(param) == type('str') and param.isnumeric() == False:
                param = random.sample(param.split(','), 1)[0]

            func = prop['LvlFunc'].values[0]
            minval = prop['MinValue'].values[0]
            maxval = prop['MaxValue'].values[0]

            try:
                if func != '':

                    if func == 'linear':
                        minval = str(minval).replace('x', str(level))
                        maxval = str(maxval).replace('x', str(level))
                        minval, maxval = math.floor(eval(minval)), math.ceil(eval(maxval))
                    elif func == 'ln':
                        x = np.log(level)

                        minval = str(minval).replace('x', str(x))
                        maxval = str(maxval).replace('x', str(x))
                        minval, maxval = math.floor(eval(minval)), math.ceil(eval(maxval))

                    minval, maxval = float(minval), float(maxval)
            except SyntaxError:
                print('ERROR')
                print(prop, func, minval, maxval)
                raise
            except ValueError:
                print('ERROR')
                print(prop, func, minval, maxval)
                raise

            if propcode == 'skill':
                param = id
            elif propcode == 'skilltab':
                param = skilltablookup[charclass][id]

            maxval = max(maxval, minval)
            setObject[f'PCode{c+2}a'] = propcode
            setObject[f'PParam{c+2}a'] = '' if pd.isna(param) else param
            setObject[f'PMin{c+2}a'] = int(minval)
            setObject[f'PMax{c+2}a'] = int(maxval)

            c += 1

        # Build full set props
        fnumprops = random.randint(numitems, 8)

        fpropertyCodes = []
        propertyType = 'fscaler'

        c = 0
        while c < fnumprops:
            prop = setPropertySelector.search_property('all', element, propertyType, fpropertyCodes, forceClass = charclass)
            propcode = prop['prop'].values[0]
            fpropertyCodes.append(propcode)

            param = prop['param'].values[0]
            if type(param) == type('str') and param.isnumeric() == False:
                param = random.sample(param.split(','), 1)[0]

            func = prop['LvlFunc'].values[0]
            minval = prop['MinValue'].values[0]
            maxval = prop['MaxValue'].values[0]

            try:
                if func != '':

                    if func == 'linear':
                        minval = str(minval).replace('x', str(level))
                        maxval = str(maxval).replace('x', str(level))
                        minval, maxval = math.floor(eval(minval)), math.ceil(eval(maxval))
                    elif func == 'ln':
                        x = np.log(level)

                        minval = str(minval).replace('x', str(x))
                        maxval = str(maxval).replace('x', str(x))
                        minval, maxval = math.floor(eval(minval)), math.ceil(eval(maxval))

                    minval, maxval = float(minval), float(maxval)
            except SyntaxError:
                print('ERROR')
                print(prop, func, minval, maxval)
                raise
            except ValueError:
                print('ERROR')
                print(prop, func, minval, maxval)
                raise

            if propcode == 'skill':
                param = id
            elif propcode == 'skilltab':
                param = skilltablookup[charclass][id]

            maxval = max(maxval, minval)
            setObject[f'FCode{c+1}'] = propcode
            setObject[f'FParam{c+1}'] = '' if pd.isna(param) else param
            setObject[f'FMin{c+1}'] = int(minval)
            setObject[f'FMax{c+1}'] = int(maxval)

            c += 1

        sets.append(setObject)

    df = pd.DataFrame(setItems)
    df.to_csv('setitems.txt', index=False, sep='\t')

    df = pd.DataFrame(sets)
    df.to_csv('sets.txt', index=False, sep='\t')

firstNames, secondNames = getNameComponents()
create_items(firstNames, secondNames)

id = 375000
jsons = []
for n in itemcache:
    jsons.append(
        {
            "id": id,
            "Key": n,
            "enUS": n
        }
    )
    id += 1

with open('names.json', 'w') as ofile:
    json.dump(jsons, ofile, indent=4)


#!/usr/bin/env python
'''
Produce a DAQ-like tree base on the hits produced by the simulation.
'''

import cowbells
import ROOT
from tree import branch
from collections import defaultdict
from array import array
import random

daq_Header = dict(
    RunNumber=          ('i',1,'Run number'),
    RunStartTime=       ('i',1,'Absolute start time in Unix epoch'),
    IsThisDataFile=     ('i',1,'Zero if MC'),
    is12or14bit=        ('i',1,'Dynamic range of FADC'),
    frequency=          ('i',1,'FADC sample rate'),
    runtype=            ('i',1,'Run type'),
    sampletype=         ('i',1,'Sample type'),
    Channel0Gain=       ('f',1,'Channel 0 gain'),
    Channel1Gain=       ('f',1,'Channel 1 gain'),
    Channel2Gain=       ('f',1,'Channel 2 gain'),
    Channel3Gain=       ('f',1,'Channel 3 gain'),
    Channel0device=     ('i',1,'Channel 0 device'),
    Channel1device=     ('i',1,'Channel 1 device'),
    Channel2device=     ('i',1,'Channel 2 device'),
    Channel3device=     ('i',1,'Channel 3 device'),
    PedestalSubstructedAtRun=('i',1,'Pedestal already subtracted'),
)
daq_Footer = dict(
    TotalEventsNumber=  ('i',1,'Number of triggers'),
    RunStopTime=        ('i',1,'Absolute stop time in Unix epoch'),
)
daq_FADCData = dict(
    Channel0=           ('H',2560,'FADC Channel 0'),
    Channel1=           ('H',2560,'FADC Channel 1'),
    Channel2=           ('H',2560,'FADC Channel 2'),
    Channel3=           ('H',2560,'FADC Channel 3'),
    EventNumber=        ('i',1,'Trigger count'),
    TriggerTimeFromRunStart=('d',1,'Time of trigger since start of run'),
)

def wash_peaks(peaks):
    ret = []
    for peak_set in peaks:
        if len(peak_set) != 1:
            continue
        peak = peak_set[0]
        t = peak['t']
        if abs(t-1525) > 25:
            continue
        ret.append(peak['q'])
    return ret

class SamplingDigitizer:
    '''
    Digitize hits using pre-sampled peak wave forms.  Peaks are of the
    form of a list of tuples holding charge samples in units of FADC
    above a pedestal and the pedestal characterized by mean/sigma.
    '''
    def __init__(self, peaks, ped):
        self.peaks = wash_peaks(peaks)
        self.ped = ped          # (mean, sigma) of pedestal
        return

    def tns_to_fadc_bin(self, tns):
        return int(tns+0.5)

    def apply_peak(self, t, sig):
        'Select a peak and apply it to signal at time t.'
        peak = random.choice(self.peaks)
        ibin = self.tns_to_fadc_bin(t) # bin for time t
        pbin = peak.index(max(peak)) # bin in peak of peak
        start = ibin-pbin+1525       # fixme: when in FADC does the peak arive?
        for count, q in enumerate(peak):
            ind = start+count
            sig[start+count] -= int(q+0.5)
            continue
    def apply_ped(self, sig, allbins = False):
        '''
        Apply pedestal.  If allbins is True add pedestal values to all
        bins, otherwise only add them to bins not yet filled.
        '''
        for ind in range(2560):
            was = sig[ind]
            if was is None or allbins:
                ped = int(0.5+random.gauss(*self.ped))
            else:
                ped = self.ped[0]

            if was is None:
                sig[ind] = 0
            sig[ind] += ped
        return

    def __call__(self, global_time, hits):
        'Return a dictionary of signals indexed by (volid,hcid)'

        signals = defaultdict(lambda: array('i',[None]*2560))

        for hit in hits:
            sig = signals[(hit.volId(),hit.hcId())]
            self.apply_peak(hit.time(), sig)
            continue
        for sig in signals.values():
            self.apply_ped(sig)
        return signals

    pass

def chidonly_mapper(volid, chid):
    return chid

class DaqTreeMaker(object):
    def __init__(self, cb_tree, digitizer, channel_map = chidonly_mapper):
        '''
        Make the tree DAQ trees in the current file using the cowbells hits tree.

        The header/footer/data trees are available from .h/.f/.d members.
        '''
        self.cb_tree = cb_tree
        self.digitizer = digitizer
        self.channel_map = channel_map

        self.h = ROOT.TTree('Header', 'DAQ header from simulation')
        self.hobj = branch(self.h, **daq_Header)
        self.f = ROOT.TTree('Footer', 'DAQ footer from simulation')
        self.fobj = branch(self.f, **daq_Footer)
        self.d = ROOT.TTree('FADCData', 'DAQ FADC data from simulation')
        self.dobj = branch(self.d, **daq_FADCData)

        return

    def __call__(self):

        for count, entry in enumerate(self.cb_tree):
            self.clear_d()
            self.dobj.EventNumber[0] = count

            hc = entry.event.hc
            vtx = entry.event.vtx
            self.dobj.TriggerTimeFromRunStart[0] = ttime = 0.0 if not len(vtx) else vtx[0].t

            triggers = self.digitizer(ttime, hc)
            for (volid,hcid), signal in triggers.iteritems():
                chn = self.channel_map(volid, hcid)
                for ind in range(2560):
                    self.dobj[chn][ind] = signal[ind]
                continue
            self.fill_d()
            continue
        self.write()
        return
    def write(self):
        '''
        Write trees to current file
        '''
        for t in (self.h, self.f, self.d):
            t.Write()

    def clear_d(self):
        for thing in self.dobj:
            for ind in range(len(thing)):
                thing[ind] = 0
        return
    def fill_d(self):
        self.d.Fill()

def proc(infilename, peaksfile, outfilename):
    infp = ROOT.TFile.Open(infilename)
    intree = infp.Get("cowbells")
    outfp = ROOT.TFile.Open(outfilename,"RECREATE")
    outfp.cd()

    import json
    peaks = json.loads(open(peaksfile).read())
    ped = (8134.5, 2.19)

    digi = SamplingDigitizer(peaks, ped)
    dtm = DaqTreeMaker(intree, digi)
    dtm()
    outfp.Close()
    return

if __name__ == '__main__':
    import sys
    proc(*sys.argv[1:4])


from app.interface.flask.state_for_action import StateDataForAction
from app.logic.events.constants import SORT_BY_START_DSC
from app.logic.events.utilities import get_list_of_events

from app.interface.html.forms import form_html_wrapper, html_button
from app.interface.html.html import Html, ListOfHtml

from app.interface.events.constants import ADD_EVENT_BUTTON_LABEL, sort_buttons
from app.interface.events.utils import row_of_form_for_event_with_buttons

def display_view_of_events(
    state_data: StateDataForAction, sort_by: str = SORT_BY_START_DSC
):
    list_of_events_with_buttons = display_list_of_events_with_buttons(sort_by=sort_by)
    add_button = html_button(ADD_EVENT_BUTTON_LABEL)

    html_inside_form = ListOfHtml(
        [
            sort_buttons,
            Html(
                "Click on any event to view/edit/delete/upload/allocate/anything else"
            ),
            add_button,
            list_of_events_with_buttons,
        ]
    ).join_as_paragraphs()

    form = form_html_wrapper(state_data.current_url)

    return form.wrap_around(html_inside_form)

def display_list_of_events_with_buttons(sort_by=SORT_BY_START_DSC) -> Html:
    list_of_events = get_list_of_events(sort_by=sort_by)

    list_with_buttons = [
        row_of_form_for_event_with_buttons(event) for event in list_of_events
    ]
    list_with_buttons_as_single_str = ListOfHtml(list_with_buttons).join_as_lines()

    return Html(list_with_buttons_as_single_str)


import time
import random

my_list = [31, 41, 59, 26, 41, 58]
my_list = list(range(0, 100000))
start_time = time.time()
# for i in range(1, 100):
random.shuffle(my_list)
my_list.sort()
print("--- %s seconds ---" % (time.time() - start_time))