from flask import (render_template, url_for, flash,
                   redirect, request, abort, Blueprint)
from flask_login import current_user, login_required
from flaskblog import db
from flaskblog.models import Post
from flaskblog.posts.forms import PostForm

posts = Blueprint('posts', __name__)

@posts.route('/post/new', methods=['GET', 'POST'])
@login_required
def new_post():
    form = PostForm()
    if form.validate_on_submit():
        post = Post(title=form.title.data, content=form.content.data, author=current_user)
        db.session.add(post)
        db.session.commit()
        flash('Your post has been created!', 'success')
        return redirect(url_for('main.home'))
    return render_template('create_post.html', title='New Post', form=form, legend='New Post')

@posts.route('/post/<int:post_id>')
def post(post_id):
    # Give post with post_id, or return 404 if it doesn't exist
    post = Post.query.get_or_404(post_id)
    return render_template('post.html', title=post.title, post=post)

@posts.route('/post/<int:post_id>/update', methods=['GET', 'POST'])
@login_required
def update_post(post_id):
    post = Post.query.get_or_404(post_id)
    if post.author != current_user:
        abort(403)
    form = PostForm()

    # Updates title and content if form is valid
    if form.validate_on_submit():
        post.title = form.title.data
        post.content = form.content.data
        db.session.commit() # No need to add, as info are already in db and we only update them
        flash('Post updated!', 'success')
        return redirect(url_for('posts.post', post_id=post.id))
    elif request.method == 'GET':
        # Fills in the update post with current data
        form.title.data = post.title
        form.content.data = post.content
    return render_template('create_post.html', title='Update Post', form=form, legend='Update Post')

@posts.route('/post/<int:post_id>/delete', methods=['POST'])
@login_required
def delete_post(post_id):
    post = Post.query.get_or_404(post_id)
    if post.author != current_user:
        abort(403)
    db.session.delete(post)
    db.session.commit()
    flash('Your post has been deleted.', 'success')
    return redirect(url_for('main.home'))


import warnings
from typing import Dict, List, Optional, Union

import numpy as np
from scipy import stats  # type: ignore
from scipy.spatial.distance import euclidean
from typing_extensions import TypedDict
from whylogs_sketching import kll_doubles_sketch  # type: ignore

from whylogs.core.utils import deprecated
from whylogs.core.view.column_profile_view import ColumnProfileView  # type: ignore
from whylogs.core.view.dataset_profile_view import DatasetProfileView  # type: ignore
from whylogs.viz.drift.configs import HellingerConfig, KSTestConfig
from whylogs.viz.utils import _calculate_bins
from whylogs.viz.utils.frequent_items_calculations import (
    FrequentStats,
    get_frequent_stats,
    zero_padding_frequent_items,
)

class ColumnDriftValue(TypedDict):
    """p-value for applied statistical test, along with the name of the applied test."""

    p_value: float
    test: str

class ColumnDriftStatistic(TypedDict):
    """Statistic for applied algorithm, along with the name of the applied algorithm."""

    statistic: float
    algorithm: str

def _compute_ks_test_p_value(
    target_distribution: kll_doubles_sketch,
    reference_distribution: kll_doubles_sketch,
    quantiles: Optional[List[float]] = None,
) -> Optional[ColumnDriftValue]:
    """Compute the Kolmogorov-Smirnov test p-value of two continuous distributions.

    Uses the quantile values and the corresponding CDFs to calculate the approximate KS statistic.
    Only applicable to continuous distributions.
    The null hypothesis expects the samples to come from the same distribution.

    Parameters
    ----------
    target_distribution : datasketches.kll_floats_sketch
        A kll_floats_sketch (quantiles sketch) from the target distribution's values
    reference_distribution : datasketches.kll_floats_sketch
        A kll_floats_sketch (quantiles sketch) from the reference (expected) distribution's values
        Can be generated from a theoretical distribution, or another sample for the same feature.
    quantiles: Optional[List[float]], optional
        Bucket of quantiles used to get the CDF's for both target and reference profiles.

    Returns
    -------
        p_value : float
        The estimated p-value from the parametrized KS test, applied on the target and reference distributions'
        kll_floats_sketch summaries

    """

    if not quantiles:
        QUANTILES = KSTestConfig().quantiles
    else:
        QUANTILES = quantiles

    if reference_distribution.is_empty() or target_distribution.is_empty():
        return None

    D_max = 0
    target_quantile_values = target_distribution.get_quantiles(QUANTILES)
    ref_quantile_values = reference_distribution.get_quantiles(QUANTILES)

    num_quantiles = len(QUANTILES)
    i, j = 0, 0
    while i < num_quantiles and j < num_quantiles:
        if target_quantile_values[i] < ref_quantile_values[j]:
            current_quantile = target_quantile_values[i]
            i += 1
        else:
            current_quantile = ref_quantile_values[j]
            j += 1

        cdf_target = target_distribution.get_cdf([current_quantile])[0]
        cdf_ref = reference_distribution.get_cdf([current_quantile])[0]
        D = abs(cdf_target - cdf_ref)
        if D > D_max:
            D_max = D

    while i < num_quantiles:
        cdf_target = target_distribution.get_cdf([target_quantile_values[i]])[0]
        cdf_ref = reference_distribution.get_cdf([target_quantile_values[i]])[0]
        D = abs(cdf_target - cdf_ref)
        if D > D_max:
            D_max = D
        i += 1

    while j < num_quantiles:
        cdf_target = target_distribution.get_cdf([ref_quantile_values[j]])[0]
        cdf_ref = reference_distribution.get_cdf([ref_quantile_values[j]])[0]
        D = abs(cdf_target - cdf_ref)
        if D > D_max:
            D_max = D
        j += 1

    m, n = sorted([target_distribution.get_n(), reference_distribution.get_n()], reverse=True)
    en = m * n / (m + n)

    p_value = stats.distributions.kstwo.sf(D_max, np.round(en))

    return {"p_value": p_value, "test": "ks"}

def _get_ks_p_value(target_view_column, reference_view_column) -> Optional[ColumnDriftValue]:
    target_dist_metric = target_view_column.get_metric("distribution")
    ref_dist_metric = reference_view_column.get_metric("distribution")

    if target_dist_metric is None or ref_dist_metric is None:
        return None

    target_kll_sketch = target_dist_metric.kll.value
    ref_kll_sketch = ref_dist_metric.kll.value

    ks_p_value = _compute_ks_test_p_value(target_kll_sketch, ref_kll_sketch)
    return ks_p_value

def _compute_chi_squared_test_p_value(
    target_distribution: FrequentStats, reference_distribution: FrequentStats
) -> Optional[ColumnDriftValue]:
    """
    Calculate the Chi-Squared test p-value for two discrete distributions.

    Uses the top frequent items summary, unique count estimate and total count estimate for each feature,
    to calculate the estimated Chi-Squared statistic.
    Applicable only to discrete distributions.

    Parameters
    ----------
    target_distribution : ReferenceDistributionDiscreteMessage
        The summary message of the target feature's distribution.
        Should be a ReferenceDistributionDiscreteMessage containing the frequent items,
        unique, and total count summaries.
    reference_distribution : ReferenceDistributionDiscreteMessage
        The summary message of the reference feature's distribution.
        Should be a ReferenceDistributionDiscreteMessage containing the frequent items,
        unique, and total count summaries.

    Returns
    -------
        p_value : ColumnDriftValue or None. ColumnDriftValue has fields `p-value` with the test's result,
        and the name of the test applied in the `test` field (chi-squared).
        The estimated p-value from the Chi-Squared test, applied on the target and reference distributions'
        frequent and unique items summaries
    """
    target_freq_items = target_distribution["frequent_items"]
    ref_freq_items = reference_distribution["frequent_items"]
    target_total_count = target_distribution["total_count"]
    target_unique_count = target_distribution["unique_count"]
    ref_total_count = reference_distribution["total_count"]

    if ref_total_count <= 0 or target_total_count <= 0:
        return None

    target_freq_items, ref_freq_items = zero_padding_frequent_items(target_freq_items, ref_freq_items)

    ref_dist_items = dict()
    for item in reference_distribution["frequent_items"]:
        ref_dist_items[item["value"]] = item["estimate"]
    proportion_ref_dist_items = {k: v / ref_total_count for k, v in ref_dist_items.items()}

    chi_sq = 0.0
    for item in target_freq_items:
        target_frequency = item["estimate"]
        if item["value"] in ref_dist_items:
            ref_frequency = int(proportion_ref_dist_items[item["value"]] * target_total_count)
        else:
            ref_frequency = 0

        if ref_frequency == 0:
            chi_sq = np.inf
            break
        chi_sq += (target_frequency - ref_frequency) ** 2 / ref_frequency

    degrees_of_freedom = target_unique_count - 1
    degrees_of_freedom = degrees_of_freedom if degrees_of_freedom > 0 else 1
    p_value = stats.chi2.sf(chi_sq, degrees_of_freedom)
    return {"p_value": p_value, "test": "chi-squared"}

def _get_chi2_p_value(target_view_column, reference_view_column) -> Optional[ColumnDriftValue]:
    target_frequent_stats: FrequentStats = get_frequent_stats(target_view_column, config=None)
    ref_frequent_stats: FrequentStats = get_frequent_stats(reference_view_column, config=None)

    if not target_frequent_stats or not ref_frequent_stats:
        return None

    chi2_p_value = _compute_chi_squared_test_p_value(
        target_distribution=target_frequent_stats, reference_distribution=ref_frequent_stats
    )
    return chi2_p_value

def calculate_hellinger_distance(target_pmf: List[float], reference_pmf: List[float]) -> float:
    """Calculates hellinger distance between two discrete probability distributions.

    Parameters
    ----------
    target_pmf : List[float]
        Target discrete probability distribution.
    reference_pmf : List[float]
        Reference discrete probability distribution.

    Returns
    -------
    float
        The hellinger distance between the two discrete probability distributions.
        Between 0 (identical distributions) and 1 (completely different distributions).
    """
    # https://en.wikipedia.org/wiki/Hellinger_distance
    distance = euclidean(np.sqrt(target_pmf), np.sqrt(reference_pmf)) / np.sqrt(2)
    return distance

def _get_hellinger_distance(
    target_view_column: ColumnProfileView,
    reference_view_column: ColumnProfileView,
    nbins: Optional[int] = None,
    config: Optional[HellingerConfig] = None,
) -> Optional[ColumnDriftStatistic]:
    if config is None:
        config = HellingerConfig()
    MAX_HIST_BUCKETS = config.max_hist_buckets
    HIST_AVG_NUMBER_PER_BUCKET = config.hist_avg_number_per_bucket
    MIN_N_BUCKETS = config.min_n_buckets
    if MIN_N_BUCKETS < 2:
        warnings.warn(
            "MIN_N_BUCKETS < 2 might lead to erroneous results for low-sized samples. Consider setting it to >=2."
        )

    if not nbins:
        nbins = MAX_HIST_BUCKETS
    target_dist_metric = target_view_column.get_metric("distribution")
    ref_dist_metric = reference_view_column.get_metric("distribution")

    if target_dist_metric is None or ref_dist_metric is None:
        warnings.warn("Column must have a Distribution Metric assigned to it.")
        return None

    target_kll_sketch = target_dist_metric.kll.value
    ref_kll_sketch = ref_dist_metric.kll.value

    if target_kll_sketch.is_empty() or ref_kll_sketch.is_empty():
        warnings.warn("Distribution sketch must not be empty.")
        return None

    start = min([target_kll_sketch.get_min_value(), ref_kll_sketch.get_min_value()])
    end = max([target_kll_sketch.get_max_value(), ref_kll_sketch.get_max_value()])
    n = target_kll_sketch.get_n() + ref_kll_sketch.get_n()
    bins, end = _calculate_bins(
        end=end,
        start=start,
        n=n,
        avg_per_bucket=HIST_AVG_NUMBER_PER_BUCKET,
        max_buckets=nbins,
        min_n_buckets=MIN_N_BUCKETS,
    )

    target_pmf = target_kll_sketch.get_pmf(bins)
    ref_pmf = ref_kll_sketch.get_pmf(bins)
    distance = calculate_hellinger_distance(target_pmf=target_pmf, reference_pmf=ref_pmf)
    return {"statistic": distance, "algorithm": "hellinger"}

@deprecated(message="please use whylogs drift's calculate_drift_score instead")
def calculate_drift_values(
    target_view: DatasetProfileView, reference_view: DatasetProfileView, statistic=False
) -> Dict[str, Optional[Union[ColumnDriftValue, ColumnDriftStatistic]]]:
    """Calculate drift values between both profiles. Applicable for numerical and categorical features.

    Calculates drift only for features found in both profiles, and ignore those not found in either profile.

    Parameters
    ----------
    target_view : DatasetProfileView
        Target Profile View
    reference_view : DatasetProfileView
        Reference Profile View
    statistic: bool
        If false, value will be a pvalue. If true value will be a statistic.

    Returns
    -------
    drift_values: Dict[str, Optional[ColumnDriftValue]]
        A dictionary of the p-values, along with the type of test applied, for the given features.
    """
    drift_values: Dict[str, Optional[Union[ColumnDriftValue, ColumnDriftStatistic]]] = {}
    target_view_columns = target_view.get_columns()
    reference_view_columns = reference_view.get_columns()
    for target_column_name in target_view_columns:
        if target_column_name in reference_view_columns:
            target_view_column = target_view_columns[target_column_name]
            reference_view_column = reference_view_columns[target_column_name]

            if not statistic:
                drift_values[target_column_name] = _get_ks_p_value(
                    target_view_column=target_view_column, reference_view_column=reference_view_column
                ) or _get_chi2_p_value(
                    target_view_column=target_view_column, reference_view_column=reference_view_column
                )
            else:
                drift_values[target_column_name] = _get_hellinger_distance(
                    target_view_column=target_view_column, reference_view_column=reference_view_column
                )
    return drift_values


import sys

input = sys.stdin.readline
MOD = 10007

# 16565 N포커
# 52개의 트럼프카드에서 n개의 카드를 고를 때
# 같은 숫자 카드를 네 문양 모두 고르는 경우가
# 한번 이상이라도 나타나는 경우의 수를 모두 구하는 문제
def sol16565():
    # 선택해야 할 카드의 수
    n = int(input())

    # 선택할 카드의 수가 4개 미만이면 이길 수 없음
    if n < 4:
        return 0

    dp = [[0] * 53 for _ in range(53)]

    for i in range(53):
        dp[i][0] = dp[i][i] = 1

    for i in range(2, 53):
        for j in range(1, i):
            dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j]) % MOD

    # 선택할 카드의 수가 40개 이상이라면 반드시 이김
    if n >= 40:
        return dp[52][n]

    # 포함 배제의 원리를 사용하여 하나 이상의 포카드를 완성하는 경우들의 합집합을 구함
    answer = 0
    for i in range(1, n // 4 + 1, 2):
        answer = (answer + dp[13][i] * dp[52 - 4 * i][n - 4 * i]) % MOD

    for i in range(2, n // 4 + 1, 2):
        answer = (answer - dp[13][i] * dp[52 - 4 * i][n - 4 * i]) % MOD

    return answer


import random
import factory
from faker import Faker
from django.core.files.base import ContentFile
from django.contrib.auth import models as auth_models
from django.utils.timezone import utc
from ninetofiver import models

fake = Faker()

class UserFactory(factory.DjangoModelFactory):
    class Meta:
        model = auth_models.User

    first_name = factory.LazyFunction(fake.first_name)
    last_name = factory.LazyFunction(fake.last_name)
    username = factory.Sequence(lambda n: 'UserName%d' % n)
    email = factory.LazyFunction(fake.name)
    is_staff = False
    is_superuser = False

class AdminFactory(UserFactory):
    is_staff = True
    is_superuser = True

class GroupFactory(factory.DjangoModelFactory):
    class Meta:
        model = auth_models.Group

    name = factory.Sequence(lambda n: 'Group%d' % n)

class CompanyFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.Company

    vat_identification_number = factory.LazyFunction(
        lambda: '%s%s' % (fake.language_code(), fake.md5()[:10])
    )
    name = factory.Sequence(lambda n: 'CompanyName%d' % n)
    address = factory.LazyFunction(fake.address)
    country = factory.LazyFunction(fake.country_code)
    internal = factory.LazyFunction(fake.boolean)

class InternalCompanyFactory(CompanyFactory):
    internal = True

class EmploymentContractTypeFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.EmploymentContractType

    name = factory.Sequence(lambda n: 'EmploymentContractType%d' % n)

class EmploymentContractFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.EmploymentContract

    started_at = factory.LazyFunction(lambda: fake.date_time_this_decade(before_now=True))
    ended_at = factory.LazyFunction(lambda: fake.date_time_this_decade(before_now=False, after_now=True))

class WorkScheduleFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.WorkSchedule

    name = factory.Sequence(lambda n: 'WorkSchedule%d' % n)
    monday = factory.LazyFunction(lambda: random.randint(0, 10))
    tuesday = factory.LazyFunction(lambda: random.randint(0, 10))
    wednesday = factory.LazyFunction(lambda: random.randint(0, 10))
    thursday = factory.LazyFunction(lambda: random.randint(0, 10))
    friday = factory.LazyFunction(lambda: random.randint(0, 10))
    saturday = factory.LazyFunction(lambda: random.randint(0, 10))
    sunday = factory.LazyFunction(lambda: random.randint(0, 10))

class UserInfoFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.UserInfo

    birth_date = factory.LazyFunction(lambda: fake.date_time_this_decade(before_now=True).date())
    gender = factory.LazyFunction(lambda: fake.simple_profile(sex=None)['sex'])
    country = factory.LazyFunction(fake.country_code)

class UserRelativeFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.UserRelative

    name = factory.LazyFunction(fake.name)
    birth_date = factory.LazyFunction(lambda: fake.date_time_this_decade(before_now=True).date())
    gender = factory.LazyFunction(lambda: fake.simple_profile(sex=None)['sex'])
    relation = factory.LazyFunction(fake.word)

class AttachmentFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.Attachment

    name = factory.LazyFunction(fake.word)
    description = factory.LazyFunction(lambda: fake.text(max_nb_chars=200))
    file = factory.LazyFunction(lambda: ContentFile(fake.text(max_nb_chars=200)))

class HolidayFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.Holiday

    name = factory.LazyFunction(fake.word)
    date = factory.LazyFunction(lambda: fake.date_time_this_decade(before_now=True))
    country = factory.LazyFunction(fake.country_code)

class LeaveTypeFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.LeaveType

    name = factory.Sequence(lambda n: 'LeaveType%d' % n)
    description = factory.LazyFunction(lambda: fake.text(max_nb_chars=200))

class LocationFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.Location

    name = factory.Sequence(lambda n: 'Location%d' % n)

class LeaveFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.Leave

    description = factory.LazyFunction(lambda: fake.text(max_nb_chars=200))

class LeaveDateFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.LeaveDate

    starts_at = factory.LazyFunction(lambda: fake.date_time_between(start_date='-1h', end_date='now', tzinfo=utc))
    ends_at = factory.LazyFunction(lambda: fake.date_time_between(start_date='now', end_date='+1h', tzinfo=utc))

class PerformanceTypeFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.PerformanceType

    name = factory.Sequence(lambda n: 'PerformanceType%d' % n)
    description = factory.LazyFunction(lambda: fake.text(max_nb_chars=200))
    multiplier = factory.LazyFunction(lambda: random.randint(0, 3))

class ContractGroupFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.ContractGroup

    name = factory.Sequence(lambda n: 'ContractGroup%d' % n)

class ContractFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.Contract

    name = factory.LazyFunction(fake.word)
    description = factory.LazyFunction(lambda: fake.text(max_nb_chars=200))
    active = factory.LazyFunction(fake.boolean)
    starts_at = factory.LazyFunction(lambda: fake.date_time_this_decade(before_now=True))
    ends_at = factory.LazyFunction(lambda: fake.date_time_this_decade(before_now=False, after_now=True))
    company = factory.SubFactory(InternalCompanyFactory)
    customer = factory.SubFactory(CompanyFactory)

class ProjectContractFactory(ContractFactory):
    class Meta:
        model = models.ProjectContract

    fixed_fee = factory.LazyFunction(lambda: random.randint(0, 9999))

class ConsultancyContractFactory(ContractFactory):
    class Meta:
        model = models.ConsultancyContract

    duration = factory.LazyFunction(lambda: random.randint(0, 9999))
    day_rate = factory.LazyFunction(lambda: random.randint(0, 9999))

class SupportContractFactory(ContractFactory):
    class Meta:
        model = models.SupportContract

    day_rate = factory.LazyFunction(lambda: random.randint(0, 9999))

class ContractRoleFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.ContractRole

    name = factory.Sequence(lambda n: 'ContractRole%d%s' % (n, fake.text(max_nb_chars=200)))
    description = factory.LazyFunction(lambda: fake.text(max_nb_chars=200))

class ContractUserFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.ContractUser

    contract_role = factory.SubFactory(ContractRoleFactory)

class ContractUserGroupFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.ContractUserGroup

class TimesheetFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.Timesheet

    month = factory.LazyFunction(lambda: random.randint(1, 12))
    year = factory.LazyFunction(lambda: random.randint(2000, 3000))

class OpenTimesheetFactory(TimesheetFactory):
    status = models.STATUS_ACTIVE

class WhereaboutFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.Whereabout

    starts_at = factory.LazyFunction(lambda: fake.date_time_between(start_date='-1h', end_date='now', tzinfo=utc))
    ends_at = factory.LazyFunction(lambda: fake.date_time_between(start_date='now', end_date='+1h', tzinfo=utc))
    location = factory.SubFactory(LocationFactory)
    timesheet = factory.SubFactory(OpenTimesheetFactory)

class PerformanceFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.Performance

    date = factory.LazyFunction(lambda: fake.date_time_this_decade().date())
    redmine_id = factory.LazyFunction(lambda: random.randint(0, 3000))

class ActivityPerformanceFactory(PerformanceFactory):
    class Meta:
        model = models.ActivityPerformance

    description = factory.LazyFunction(lambda: fake.text(max_nb_chars=200))
    duration = factory.LazyFunction(lambda: random.randint(1, 24))
    contract_role = ContractRoleFactory

class StandbyPerformanceFactory(PerformanceFactory):
    class Meta:
        model = models.StandbyPerformance


#!/usr/bin/env python3

"""
Author: Ian Coleman
Purpose: Coding challenge

"""

import pdb

def new_grid(n):
    grid = []

    column_numbers = [str(x) for x in range(1, n + 1)]
    first_line = "  " + "  ".join(column_numbers)
    grid.append(first_line)

    horizontal_unit = "+--"
    vertical_unit = "|  "

    for row in range(1, n + 1):
        grid += [" " + (horizontal_unit * n) + "+"]
        grid += [str(row) + (vertical_unit * n) + "|"]
    grid += [" " + (horizontal_unit * n) + "+"]

    return grid

def print_grid(grid):
    [print(x) for x in grid]

def delete_v(g, i, j):
    """ Delete a column seperator """
    if i == 1:
        converted_row =  2
    else:
        converted_row = 2 + (2 * (i - 1))
    converted_column = ((j) * 2) + (j + 1)

    string_to_change = g[converted_row]
    new_string = string_to_change[:converted_column] \
        + " " + string_to_change[converted_column + 1:]
    g[converted_row] = new_string

    return grid

def delete_h(g, i, j):
    """ Delete a row seperator """
    # pdb.set_trace()
    if i == 1:
        converted_row = 3
    else:
        converted_row = 3 + (2 * (i - 1))
    converted_column = ((j - 1) * 2) + j + 1

    string_to_change = g[converted_row]
    new_string = string_to_change[:converted_column] \
        + "  " + string_to_change[converted_column + 2:]
    g[converted_row] = new_string

    return grid

if __name__ == "__main__":
    grid = new_grid(5)
    print_grid(grid)
    new_grid = delete_v(grid, 1, 1)
    new_grid = delete_h(new_grid, 1, 1)
    print_grid(new_grid)


#!/usr/bin/env python
# https://stackoverflow.com/questions/26656943/how-to-get-data-in-python-from-ros-in-real-time
import rospy
from std_msgs.msg import String
from nav_msgs.msg import Odometry
def callback(data):
    rospy.loginfo(rospy.get_caller_id()+"I heard %s",data)

def listener():
    rospy.init_node('listener', anonymous=True)
    rospy.Subscriber("odom", Odometry, callback)
    rospy.spin()

if __name__ == '__main__':
    listener()


import unittest
import os
import time
import csv

from flow.core.experiment import Experiment
from flow.core.params import VehicleParams
from flow.controllers import IDMController, RLController, ContinuousRouter
from flow.core.params import SumoCarFollowingParams
from flow.core.params import SumoParams
from flow.core.params import EnvParams, InitialConfig, NetParams
from flow.core.params import TrafficLightParams
from flow.envs import AccelEnv
from flow.networks import RingNetwork

from tests.setup_scripts import ring_road_exp_setup

import numpy as np

os.environ["TEST_FLAG"] = "True"

class TestNumSteps(unittest.TestCase):
    """
    Tests that experiment class runs for the number of steps requested.
    """

    def setUp(self):
        # create the environment and network classes for a ring road
        env, _, flow_params = ring_road_exp_setup()
        flow_params['sim'].render = False
        flow_params['env'].horizon = 10
        # instantiate an experiment class
        self.exp = Experiment(flow_params)
        self.exp.env = env

    def tearDown(self):
        # free up used memory
        self.exp = None

    def test_steps(self):
        self.exp.run(num_runs=1)

        self.assertEqual(self.exp.env.time_counter, 10)

class TestNumRuns(unittest.TestCase):
    """
    Tests that the experiment class properly resets as many times as requested,
    after the correct number of iterations.
    """

    def test_num_runs(self):
        # run the experiment for 1 run and collect the last position of all
        # vehicles
        env, _, flow_params = ring_road_exp_setup()
        flow_params['sim'].render = False
        flow_params['env'].horizon = 10
        exp = Experiment(flow_params)
        exp.env = env
        exp.run(num_runs=1)

        vel1 = [exp.env.k.vehicle.get_speed(exp.env.k.vehicle.get_ids())]

        # run the experiment for 2 runs and collect the last position of all
        # vehicles
        env, _, flow_params = ring_road_exp_setup()
        flow_params['sim'].render = False
        flow_params['env'].horizon = 10

        exp = Experiment(flow_params)
        exp.env = env
        exp.run(num_runs=2)

        vel2 = [exp.env.k.vehicle.get_speed(exp.env.k.vehicle.get_ids())]

        # check that the final position is the same in both instances
        np.testing.assert_array_almost_equal(vel1, vel2)

class TestRLActions(unittest.TestCase):
    """
    Test that the rl_actions parameter acts as it should when it is specified,
    and does not break the simulation when it is left blank.
    """

    def test_rl_actions(self):
        def rl_actions(*_):
            return [1]  # actions are always an acceleration of 1 for one veh

        # create an environment using AccelEnv with 1 RL vehicle
        vehicles = VehicleParams()
        vehicles.add(
            veh_id="rl",
            acceleration_controller=(RLController, {}),
            routing_controller=(ContinuousRouter, {}),
            car_following_params=SumoCarFollowingParams(
                speed_mode="aggressive",
            ),
            num_vehicles=1)

        env, _, flow_params = ring_road_exp_setup(vehicles=vehicles)
        flow_params['sim'].render = False
        flow_params['env'].horizon = 10
        exp = Experiment(flow_params)
        exp.env = env
        exp.run(1, rl_actions=rl_actions)

        # check that the acceleration of the RL vehicle was that specified by
        # the rl_actions method
        self.assertAlmostEqual(exp.env.k.vehicle.get_speed("rl_0"), 1,
                               places=1)

class TestConvertToCSV(unittest.TestCase):
    """
    Tests that the emission files are converted to csv's if the parameter
    is requested.
    """

    def test_convert_to_csv(self):
        dir_path = os.path.dirname(os.path.realpath(__file__))
        sim_params = SumoParams(emission_path="{}/".format(dir_path))

        vehicles = VehicleParams()
        vehicles.add(
            veh_id="idm",
            acceleration_controller=(IDMController, {}),
            routing_controller=(ContinuousRouter, {}),
            car_following_params=SumoCarFollowingParams(
                speed_mode="aggressive",
            ),
            num_vehicles=1)

        additional_env_params = {
            "target_velocity": 8,
            "max_accel": 1,
            "max_decel": 1,
            "sort_vehicles": False,
        }
        env_params = EnvParams(
            horizon=10,
            additional_params=additional_env_params)

        additional_net_params = {
            "length": 230,
            "lanes": 1,
            "speed_limit": 30,
            "resolution": 40
        }
        net_params = NetParams(additional_params=additional_net_params)

        flow_params = dict(
            exp_tag="RingRoadTest",
            env_name=AccelEnv,
            network=RingNetwork,
            simulator='traci',
            sim=sim_params,
            env=env_params,
            net=net_params,
            veh=vehicles,
            initial=InitialConfig(lanes_distribution=1),
            tls=TrafficLightParams(),
        )

        exp = Experiment(flow_params)
        exp.run(num_runs=1, convert_to_csv=True)

        time.sleep(1.0)

        # check that both the csv file exists and the xml file doesn't.
        self.assertFalse(os.path.isfile(dir_path + "/{}-0_emission.xml".format(
            exp.env.network.name)))
        self.assertTrue(os.path.isfile(dir_path + "/{}-0_emission.csv".format(
            exp.env.network.name)))

        # check that the keys within the emission file matches its expected
        # values
        with open(dir_path + "/{}-0_emission.csv".format(
                exp.env.network.name), "r") as f:
            reader = csv.reader(f)
            header = next(reader)

        self.assertListEqual(header, [
            "time",
            "id",
            "x",
            "y",
            "speed",
            "headway",
            "leader_id",
            "target_accel_with_noise_with_failsafe",
            "target_accel_no_noise_no_failsafe",
            "target_accel_with_noise_no_failsafe",
            "target_accel_no_noise_with_failsafe",
            "realized_accel",
            "road_grade",
            "edge_id",
            "lane_number",
            "distance",
            "relative_position",
            "follower_id",
            "leader_rel_speed",
        ])

        time.sleep(0.1)

        # delete the files
        os.remove(os.path.expanduser(dir_path + "/{}-0_emission.csv".format(
            exp.env.network.name)))

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


def tfidf_Vec_train(data):

    ##imports
    from sklearn.feature_extraction.text import TfidfVectorizer
    import joblib
    import os

    tfidf_vectorizer = TfidfVectorizer(use_idf=True,max_df=0.5)
    vectors = tfidf_vectorizer.fit_transform(data)
    with open(os.path.join("Embedding","similarity.features"),"wb") as f:
        joblib.dump(vectors,f)

def tfidf_Vec_similarity(data):

    ##imports
    from sklearn.feature_extraction.text import TfidfVectorizer

    tfidf_vectorizer = TfidfVectorizer(use_idf=True,max_df=0.5)
    vectors = tfidf_vectorizer.fit_transform(data)
    vectors = vectors.toarray()
    vec_list = []
    for ele in vectors:
        vec_list.append(ele)
    return vec_list


OPTIMIZE = True

class OPBase:
    _eval_cache = dict()
    _shardable_options_cache = dict()
    type_name = ""

    @classmethod
    def tokenrize(cls, tensor):
        from ..tensor import Tensor

        op_attr = tensor.op_attr
        x1_shape = tensor.x1_shape
        x2_shape = tensor.x2_shape
        x1_hidden = tensor.x1_hidden
        x2_hidden = tensor.x2_hidden

        x1_shape_str = (
            Tensor.stringfy_shape(x1_shape) if x1_shape is not None else "None"
        )
        x2_shape_str = (
            Tensor.stringfy_shape(x2_shape) if x2_shape is not None else "None"
        )
        x1_hidden_str = (
            Tensor.stringfy_shape(x1_hidden) if x1_hidden is not None else "None"
        )
        x2_hidden_str = (
            Tensor.stringfy_shape(x2_hidden) if x2_hidden is not None else "None"
        )
        op_attr_str = op_attr if not op_attr is None else "None"
        token = (
            cls.type_name
            + x1_shape_str
            + x2_shape_str
            + x1_hidden_str
            + x2_hidden_str
            + op_attr_str
        )
        return token

    @classmethod
    def eval(cls, tensor):
        token = cls.tokenrize(tensor)
        if token in cls._eval_cache:
            return cls._eval_cache[token]
        cls._sanity_check(tensor)
        direct_output_shape, direct_output_hidden, num_ops = cls._eval_impl(tensor)
        cls._eval_cache[token] = direct_output_shape, direct_output_hidden, num_ops
        return direct_output_shape, direct_output_hidden, num_ops

    @classmethod
    def shardable_options(cls, tensor):
        token = cls.tokenrize(tensor)
        if token in cls._shardable_options_cache:
            return cls._shardable_options_cache[token]
        cls._sanity_check(tensor)
        shardable_options = cls._shardable_options_impl(tensor)
        cls._shardable_options_cache[token] = shardable_options
        return shardable_options

    @classmethod
    def _sanity_check(cls, tensor):
        raise NotImplementedError()

    @classmethod
    def _eval_impl(cls, tensor):
        raise NotImplementedError()

    @classmethod
    def _shardable_options_impl(cls, tensor):
        raise NotImplementedError()


import numpy as np
from numpy import pi,cos,sin,array,matmul
from kinematic_model_num import planar_angle, Rx, Rz, get_kin_data
from find_cycles import find_cycles
from tritri_intsec_check import NoDivTriTriIsect
import matplotlib.pyplot as plt

def search_bnd_vtx_within_symmetry(env, start_vtx, upper_bound_bln: bool):
# ------------------------------------------------------------------------------
#
#   Search for the next boundary vertex within the symmetry bounds
#
#   takes:      vtx: vertex2extend obj
#               upper_bound_bln:    True for searching upper (CW) boundary vertex,
#                                   False for lower (CCW) boundary vertex
#
#   returns:    bnd_vtx: name of boundary vertex or vertex on symmetry axis
#               bool: whether the vertex was found within the symmetry
#
# ------------------------------------------------------------------------------
    idx_delta = -1 if upper_bound_bln else +1
    start_on_symmetry_axis = is_on_symmetry_axis(env, start_vtx.name)
    vertex_to_check = start_vtx.surrounding_vertices[-1] if upper_bound_bln else start_vtx.surrounding_vertices[0]
    vtx_obj = env.vertex_objs[vertex_to_check]
    idx = vtx_obj.surrounding_vertices.index(start_vtx.name)
    previous_vtx = start_vtx.name
    while True:
        if crossed_symmetry_axis(env, start_vtx, vtx_obj):
            return previous_vtx, True
        elif not vtx_obj.is_extended:
            return vertex_to_check, False
        else:
            if start_on_symmetry_axis and not is_on_symmetry_axis(env, vertex_to_check):
                start_vtx = vtx_obj
            num_sv = len(vtx_obj.surrounding_vertices)
            previous_vtx = vertex_to_check
            vertex_to_check = vtx_obj.surrounding_vertices[(idx+idx_delta)%num_sv]
            new_vtx_obj = env.vertex_objs[vertex_to_check]
            idx = new_vtx_obj.surrounding_vertices.index(vtx_obj.name)
            vtx_obj = new_vtx_obj

def crossed_symmetry_axis(env, start_vtx, vtx_obj):
    if not env.symmetry:
        return False
    xs,ys = env.points_2D[start_vtx.name]
    xn,yn = env.points_2D[vtx_obj.name]
    if env.symmetry_axis == 'x-axis':
        return ys * yn < 0
    elif env.symmetry_axis == 'y-axis':
        return xs * xn < 0
    elif env.symmetry_axis == 'point':
        tmp_bool = False
        if env.cross_axis_symmetry:
            tmp_bool = (xs - ys) * (xn - yn) < 0
        return xs * xn < 0 or ys * yn < 0 or tmp_bool
    else:
        raise NotImplementedError

def is_on_symmetry_axis(env, vtx):
    if not env.symmetry:
        return False
    x,y = env.points_2D[vtx]
    if env.symmetry_axis == 'x-axis':
        return y == 0.
    elif env.symmetry_axis == 'y-axis':
        return x == 0.
    elif env.symmetry_axis == 'point':
        tmp_bool = False
        if env.cross_axis_symmetry:
            tmp_bool = abs(x)==abs(y)
        return x==0. or y==0 or tmp_bool
    else:
        raise NotImplementedError

class PseudoVertex():
    def __init__(self, env, name, key, coords_2D, coords_3D, neighbor):
        self.name = name
        self.key = key
        self.coords = coords_2D
        self.coords_3D = coords_3D
        self.neighbor = neighbor
        self.is_pseudo = True
        self.inactive = False
        self.env = env
        env.vertex_pos_list.append(self.__map2board(coords_2D))

    def __map2board(self,new_points_2D):

        new_vertex_pos = []
        if len(new_points_2D)==2:
            new_vertex_pos = [int(self.env.half_board_length - new_points_2D[1]), int(self.env.half_board_length + new_points_2D[0])]
        else:
            for coord_x,coord_y in new_points_2D:
                new_vertex_pos.append([int(self.env.half_board_length - coord_y), int(self.env.half_board_length + coord_x)])

        return new_vertex_pos

class SingleVertex():
# ------------------------------------------------------------------------------
#
#   A Single Vertex (SV) is the basic primitive of a PTU based rigid origami
#   model and crease pattern. A PTU rigid origami crease pattern consists of
#   multiple interlinked SV's.
#   SV's are linked by edges and inherit dihedral angle values phi to child SV's.
#
#   properties:     name (int)
#                   coords [x,y]
#                   coords_3D [3,float]
#                   mother_vertex [int]
#                   driving_angle [float list]
#                   surrounding_vertices [int list]
#                   surrounding_c_len [float list]
#                   rbm [1,2]
#                   phi [3,float]
#                   polygons [int list]
#                   init_rot [3x3 array]
#                   extended (boolean)
#
#   public methods: extend(rbm,ext_vertex_coords)
#
# ------------------------------------------------------------------------------

    def __init__(   self,
                    env_obj,
                    name,
                    coords,
                    mother_vertex_name,
                    driving_angle,
                    c_len=1,
                    init_rot=Rz(0),
                    units=[],
                    mirrored=False,
                    new_vertex=True,
                    rbm=1):
        # ----- initialize single vertex properties -----
        self.env = env_obj
        self.name = name
        self.is_pseudo = False
        self.coords = np.asarray(coords)
        self.coords_3D = np.array([[coords[0],coords[1],0] for _ in range(len(self.env.psi_opt))])
        self.mother_vertex = mother_vertex_name
        self.init_rot = init_rot if isinstance(init_rot,list) else [init_rot for _ in range(len(self.env.psi_opt))]
        self.board_pos = self.__map2board(coords)
        self.surrounding_vertices = [mother_vertex_name]
        self.surr_c_len = [c_len]
        self.unit_angles = []
        self.sector_angles = []
        self.dihedral_angles = driving_angle
        self.units = units
        self.is_extended = False
        self.is_mirrored = mirrored
        self.rbm = rbm
        self.__update_board_state([self.board_pos])
        self.update_adjacency_state([[name,mother_vertex_name]])
        if new_vertex:
            self.env.vertex_pos_list.append(self.board_pos)
            self.env.points_2D.append(coords)
        self.polygons = []

# ------------------------------------------------------------------------------
# ----- public methods ---------------------------------------------------------
# ------------------------------------------------------------------------------

    def extend(self,rbm,ext_vertex_coords_ro):
    # --------------------------------------------------------------------------
    #
    #   takes:      rbm: rigid body mode (int)
    #               ext_vertex_coordinates: a list of 2D coordinates for the
    #                   three new extension vertices
    #
    #   ->          creates and initializes three new vertices from self
    #   ->          updates properties of surrounding vertices
    #   ->          updates env variables, including state
    #
    #   returns:    -
    #
    # --------------------------------------------------------------------------

        ext_vertex_names = []
        ext_board_coords = self.__map2board(ext_vertex_coords_ro)
        new_i = []
        upgrade_i = []
        merge_i = []
        c_len = []
        self.new_faces = []
        self.env.face_boundary_edges = [edge for edge in self.env.face_boundary_edges if self.name not in edge]
        vertex_list_orig = self.env.vertex_list.copy()
        vertex_objs_orig = self.env.vertex_objs.copy()

        for i in range(len(ext_vertex_coords_ro)):
#            ii,jj = ext_board_coords[i]
            # === test for merge candidates
            if  ext_vertex_coords_ro[i] in self.env.points_2D: #not self.env.state[ii,jj,0] == 0:
                vtx_obj = self.env.vertex_objs[self.env.points_2D.index(ext_vertex_coords_ro[i])]
                ext_vertex_names.append(vtx_obj.name)#self.env.vertex_pos_list.index(ext_board_coords[i])) #find existing vertex
                if vtx_obj.is_pseudo and not vtx_obj.inactive:
                    upgrade_i.append(i)
                else:
                    merge_i.append(i)
            else:
                new_vertex = len(self.env.vertex_list)
                self.env.vertex_list.append(new_vertex)
                ext_vertex_names.append(new_vertex)
                new_i.append(i)
            c_len.append(np.linalg.norm(ext_vertex_coords_ro[i]-self.coords))

        # --- search boundary vertices for outer faces (before updating surrounding vertices of self)
        bnd_vtx_zip = []
        for idx, vtx in enumerate(ext_vertex_names[:-1]):  # nothing to do on middle extended node (at idx=2)
            bnd_vtx, on_symmetry = search_bnd_vtx_within_symmetry(self.env, self, idx != 0)
            bnd_vtx_zip.append((bnd_vtx, on_symmetry, vtx))

        # --- update list of surrounding vertices
        self.surrounding_vertices.insert(0,ext_vertex_names[0])
        self.surrounding_vertices.extend(ext_vertex_names[1:])
        self.surr_c_len.insert(0,c_len[0])
        self.surr_c_len.extend(c_len[1:])

        # --- new vertex instances
        # self.env.len_new_vertices = len(new_i)  # TODO necessary?
        for i in new_i:
            self.env.vertex_objs.append(SingleVertex(self.env, ext_vertex_names[i], ext_vertex_coords_ro[i],
                                                     self.name, 0, c_len[i]))
        for i in upgrade_i:
            key = self.env.vertex_objs[ext_vertex_names[i]].key
            self.env.vertex_objs[ext_vertex_names[i]] = SingleVertex(self.env, ext_vertex_names[i],
                                                                     ext_vertex_coords_ro[i], self.name, 0,
                                                                     c_len[i], new_vertex=False)
            del self.env.pseudo_vertices[key]

        # --- determine single vertex PTU kinematics and derive output folding angles phi
        self.rbm = rbm
        units,phi,multi_new_points_3D,multi_point_transforms,U = \
            self.__single_vertex_kinematics(c_len)
        polygons = self.__get_polygon_list(self.surrounding_vertices)

        # --- update board state
        self.__update_board_state([self.board_pos],rbm)
        # --- reset selection
        self.env.state[:,:,-1] = 0

        # --- update unit property
        self.units = units

        # --- update existing adjacent vertices
        new_edges = [[self.name,name] for name in ext_vertex_names]
        self.update_adjacency_state(new_edges)

        for i in merge_i:
            if i==0:
                is_u_bnd = True
            else:
                is_u_bnd = False
            self.__update_merged_vertex(ext_vertex_names[i],multi_point_transforms[i],self.phi[:,i],c_len[i],new_edges,is_u_bnd)

        for i in new_i:
            self.__update_new_vertex(ext_vertex_names[i],multi_new_points_3D[i,:,:].T,multi_point_transforms[i],self.phi[:,i],new_edges)
        for i in upgrade_i:
            self.__update_new_vertex(ext_vertex_names[i],multi_new_points_3D[i,:,:].T,multi_point_transforms[i],self.phi[:,i],new_edges)

        # --- update edge_list
        for v in ext_vertex_names:
            self.env.edge_list.append([self.name,v])

        # --- add faces between extended vertices
        self.new_faces.append([self.name, ext_vertex_names[0], ext_vertex_names[2]])
        self.env.face_boundary_edges.append([ext_vertex_names[0], ext_vertex_names[2]])
        self.new_faces.append([self.name, ext_vertex_names[1], ext_vertex_names[2]])
        self.env.face_boundary_edges.append([ext_vertex_names[1], ext_vertex_names[2]])

        # --- add outer faces
        for bnd_vtx, on_symmetry, vtx in bnd_vtx_zip:
            if on_symmetry:
                bnd_vtx = self.__create_or_update_pseudo_vtx(bnd_vtx, vtx)
            if not bnd_vtx == vtx: # no face needs to be added on merges
                if vtx in [ext_vertex_names[i] for i in upgrade_i]: continue # upgraded vertices don't need this face
                self.new_faces.append([self.name, vtx, bnd_vtx])
                self.env.face_boundary_edges.append([vtx, bnd_vtx])

        self.polygons = polygons # TODO necessary?

        self.env.triangles.extend(self.new_faces)
        # === no foldability check per default if no numerical optimal
        # === fold angle psi_opt specified
        foldable = True
        msg = "no foldabilty check for non-symbolic evaluation"
        self.is_extended = True
        foldable, msg = self.check_foldability(ext_vertex_names)  # polygons)
        return foldable, msg

# ------------------------------------------------------------------------------
# ----- private methods ---------------------------------------------------------
# ------------------------------------------------------------------------------

    def __map2board(self,new_points_2D):

        new_vertex_pos = []
        if len(new_points_2D)==2:
            new_vertex_pos = [int(self.env.half_board_length - new_points_2D[1]), int(self.env.half_board_length + new_points_2D[0])]
        else:
            for coord_x,coord_y in new_points_2D:
                new_vertex_pos.append([int(self.env.half_board_length - coord_y), int(self.env.half_board_length + coord_x)])

        return new_vertex_pos

    def __update_board_state(self,new_vertex_pos,rbm=1):
        if rbm >= 0:
            board_rbm = 1
        else:
            board_rbm = -1
        for coords_x,coords_y in new_vertex_pos:
            self.env.state[coords_x,coords_y,0] = board_rbm
        return self.env.state[:,:,0]

    def update_adjacency_state(self,new_edges):
        for v_pos_centr,v_pos_out in new_edges:
            if self.name in (v_pos_centr,v_pos_out):
                if v_pos_out == self.name:
                    self.env.state[self.board_pos[0],self.board_pos[1],(v_pos_centr+1)] = -1
                else:
                    self.env.state[self.board_pos[0],self.board_pos[1],int(v_pos_out+1)] = 1

    def __update_merged_vertex(self,v,start_rot,inc_phi,c_len,new_edges,is_u_bnd):
        vtx = self.env.vertex_objs[v]
        vtx.update_adjacency_state(new_edges)

        inc_phi = inc_phi.reshape((-1,1))

        # u_bnd for upper bound appending, False otherwise
        if is_u_bnd:
            vtx.surrounding_vertices.append(self.name)
            vtx.dihedral_angles = np.hstack((vtx.dihedral_angles,inc_phi))
            vtx.surr_c_len.append(c_len)

        else:
            vtx.surrounding_vertices.insert(0,self.name)
            vtx.dihedral_angles = np.hstack((inc_phi,vtx.dihedral_angles))
            vtx.surr_c_len.insert(0,c_len)
            vtx.init_rot = start_rot

        # MIURA ORI
        # if len(vtx.surrounding_vertices) == 2:
        #     # if True: check whether edges colinear, than mark as is_extended
        #     # this will allow the modeling of patterns like the Miura Ori
        #     a,b = vtx.surrounding_vertices
        #     coords_a, coords_b = self.env.points_2D[a], self.env.points_2D[b]
        #     if coords_a[0] == coords_b[0] == vtx.coords[0] or \
        #         coords_a[1] == coords_b[1] == vtx.coords[1]:
        #         vtx.is_extended = True

    def __update_new_vertex(self, v: int, point_3D, init_rot, inc_phi, new_edges):
        vtx = self.env.vertex_objs[v]
        vtx.coords_3D = point_3D
        vtx.init_rot = init_rot
        vtx.dihedral_angles = inc_phi.reshape((-1,1))
        vtx.update_adjacency_state(new_edges)

    def __create_or_update_pseudo_vtx(self, bnd_vtx, vtx):
        x, y = self.env.points_2D[bnd_vtx]
        vtx_x, vtx_y = self.env.points_2D[vtx]
        sym_axis = self.env.symmetry_axis
        switchpoint = sum(self.env.points_2D[0])
        if self.env.symmetry_axis == 'point':
            switchpoint = 0
            if x == 0:
                sym_axis = 'y-axis'
            elif y == 0:
                sym_axis = 'x-axis'
            elif x == y:
                sym_axis = 'xy'
            else:
                raise NotImplementedError
        if sym_axis == 'x-axis':
            assert y == 0
            key = 'x+' if vtx_x > switchpoint else 'x-'
            coords_2D = vtx_x, 0.
            coords_3D = self.env.vertex_objs[vtx].coords_3D.copy()
            coords_3D[:, 1] = 0.
            return self.__pseudo_vtx_helper(key, bnd_vtx, vtx, coords_2D, coords_3D)
        elif sym_axis == 'y-axis':
            assert x == 0
            key = 'y+' if vtx_y > switchpoint else 'y-'
            coords_2D = 0., vtx_y
            coords_3D = self.env.vertex_objs[vtx].coords_3D.copy()
            coords_3D[:, 0] = 0.
            return self.__pseudo_vtx_helper(key, bnd_vtx, vtx, coords_2D, coords_3D)
        elif sym_axis == 'xy':
            assert x == y
            if vtx_x > switchpoint and vtx_y > switchpoint:
                key = 'xy++'
            elif vtx_x > switchpoint and vtx_y < switchpoint:
                key = 'xy+-'
            elif vtx_x < switchpoint and vtx_y > switchpoint:
                key = 'xy-+'
            else:
                key = 'xy--'
            unsigned_average = 0.5 * (abs(vtx_x) + abs(vtx_y))
            coords_2D = np.sign(vtx_x) * unsigned_average, np.sign(vtx_y) * unsigned_average
            coords_3D = self.env.vertex_objs[vtx].coords_3D.copy()
            unsigned_averages = 0.5 * (np.abs(coords_3D[:, 0]) + np.abs(coords_3D[:, 1]))
            coords_3D[:, 0] = np.sign(coords_3D[:, 0]) * unsigned_averages
            coords_3D[:, 1] = np.sign(coords_3D[:, 1]) * unsigned_averages
            return self.__pseudo_vtx_helper(key, bnd_vtx, vtx, coords_2D, coords_3D)
        raise NotImplementedError  # currently, cross symmetry not yet implemented

    def __pseudo_vtx_helper(self, key, bnd_vtx, vtx, coords_2D, coords_3D):
        coords_2D = [int(coords_2D[0]), int(coords_2D[1])]
        if key in self.env.pseudo_vertices:
            # update pseudo vertex
            pseudo_vtx, msg = self.env.pseudo_vertices[key]
            if msg == 'del':  # pseudo vertex marked for deletion if vtx on symmetry axis
                del self.env.pseudo_vertices[key]  # this ensures a new face gets a new pseudo vertex
                return vtx
            elif msg == 'new':
                # if we create a pseudo vertex, we also have to add the pseudo vertex face
                self.new_faces.append([pseudo_vtx, bnd_vtx, vtx])
                self.env.face_boundary_edges.append([pseudo_vtx, vtx])
                self.env.pseudo_vertices[key] = (pseudo_vtx, '')
                return bnd_vtx  # return bnd_vtx here, such that outerface gets filled to bound vtx

            # update
            self.env.points_2D[pseudo_vtx] = coords_2D
            self.env.vertex_objs[pseudo_vtx].coords = coords_2D
            self.env.vertex_objs[pseudo_vtx].coords_3D = coords_3D
            self.env.vertex_objs[pseudo_vtx].neighbor = vtx
            self.env.vertex_pos_list[pseudo_vtx] = self.__map2board(coords_2D)

            if is_on_symmetry_axis(self.env, vtx):
                # self.env.vertex_objs[pseudo_vtx] = self.env.vertex_objs[vtx]  # refer full vertex
                self.env.vertex_objs[pseudo_vtx].name = vtx
                self.env.vertex_objs[pseudo_vtx].inactive = True
                self.env.pseudo_vertices[key] = (pseudo_vtx, 'del')  # delete pseudo vertex after symmetry expansion
                return vtx
            return pseudo_vtx
        elif is_on_symmetry_axis(self.env, vtx):
            # no need to create a pseudo vertex
            return bnd_vtx  # return bnd_vtx here, such that outerface gets filled to bound vtx
        else:
            pseudo_vtx = len(self.env.vertex_list)
            self.env.vertex_list.append(pseudo_vtx)
            self.env.points_2D.append(coords_2D)
            self.env.vertex_objs.append(PseudoVertex(self.env, pseudo_vtx, key, coords_2D, coords_3D, vtx))
            self.env.vertex_pos_list.append(self.__map2board(coords_2D))
            # print('created pseudo node ' + key, pseudo_vtx, coords_2D, coords_3D)
            self.env.pseudo_vertices[key] = (pseudo_vtx, 'new')
            # if we create a pseudo vertex, we also have to add the pseudo vertex face
            self.new_faces.append([pseudo_vtx, bnd_vtx, vtx])
            self.env.face_boundary_edges.append([pseudo_vtx, vtx])
            return bnd_vtx  # return bnd_vtx here, such that outerface gets filled to bound vtx

    def __single_vertex_kinematics(self, c_len: list):
    # --------------------------------------------------------------------------
    #
    #   takes:      c_len: a list of adjacent edge lengths, starting from the
    #                   first unit vertex
    #
    #   returns:    self.units: unit angles of single vertex
    #               phi_vec: list of three outgoing edge driving angles
    #               [point_1,point_2,point_3]: new outgoing point 3D coordinates
    #
    # --------------------------------------------------------------------------

        # --- get sector angles
        sector_angles = []
        for i in range(len(self.surrounding_vertices)-1):
            sector_angles.append(planar_angle(\
            self.env.vertex_objs[self.surrounding_vertices[i]].coords - self.coords,\
            self.env.vertex_objs[self.surrounding_vertices[i+1]].coords - self.coords))
        sector_angles.append(planar_angle(\
        self.env.vertex_objs[self.surrounding_vertices[-1]].coords - self.coords,\
        self.env.vertex_objs[self.surrounding_vertices[0]].coords - self.coords))

        # --- assemble sector angles list per unit
        self.units = [sector_angles[0:-2],[sector_angles[-2]],[sector_angles[-1]]]

        # starting edge for forward kinematics
        #should always set equal to one -> first incoming edge on lower bound
        start_pos = 1

        num_valid_fold_angles = np.count_nonzero(self.env.triangle_inequality_holds)
        diff = self.env.triangle_inequality_holds.size - num_valid_fold_angles
        init_rot = np.array(self.init_rot.copy()[diff:])

        # --- get unknown dihedral angles phi
        phi,self.out_points_3D,point_transforms,U,self.dihedral_angles,triangle_inequality_holds = \
            get_kin_data(
                num_valid_fold_angles,
                self.rbm,
                self.units.copy(),
                self.dihedral_angles.copy()[self.env.triangle_inequality_holds],
                init_rot)

        # --- assemble list of 3D points dependent on enval driving angle psi
        multi_transforms2pass = [[],[],[]]
        for j in range(diff):
            multi_transforms2pass[0].append([None])
            multi_transforms2pass[1].append([None])
            multi_transforms2pass[2].append([None])
        multi_points2pass = np.ones((3,3,len(self.env.psi_opt)))
        for i in range(num_valid_fold_angles):
            j = i+diff
            multi_points2pass[0,:,j] = c_len[0]*(self.out_points_3D[i][-1-start_pos])+self.coords_3D[j,:]
            multi_points2pass[1,:,j] = c_len[1]*(self.out_points_3D[i][-3-start_pos])+self.coords_3D[j,:]
            multi_points2pass[2,:,j] = c_len[2]*(self.out_points_3D[i][-2-start_pos])+self.coords_3D[j,:]
            multi_transforms2pass[0].append(point_transforms[i][-1-start_pos])
            multi_transforms2pass[1].append(point_transforms[i][-3-start_pos])
            multi_transforms2pass[2].append(point_transforms[i][-2-start_pos])

        self.U = U
        # make sure triangle inequality holds also for prior extensions
        triangle_inequality_holds = np.hstack((np.zeros(diff),triangle_inequality_holds))
        self.env.triangle_inequality_holds = \
            np.logical_and(triangle_inequality_holds,self.env.triangle_inequality_holds)
        if diff>0:
            phi = np.vstack((np.zeros((diff,np.shape(phi)[1])),phi))
        new_phi = np.roll(phi,1,axis=1)
        self.phi = new_phi

        return self.units,new_phi,multi_points2pass,multi_transforms2pass,U

    def __get_polygon_list(self, verts: list):
    # --------------------------------------------------------------------------
    #
    #   takes:      verts: a list of surrounding vertices of a single vertex
    #
    #   returns:    poly_verts: a list of triangular face definitions
    #                   [vertex_#,vertex_#,vertex_#],
    #                   each adjacent to the central single vertex
    #
    # --------------------------------------------------------------------------

        poly_verts = np.zeros((len(verts),3),dtype=int)
        poly_verts[:,0] = verts
        poly_verts[:-1,1] = verts[1:]
        poly_verts[-1,1] = verts[0]
        poly_verts[:,2] = [self.name for _ in range(len(verts))]

        return poly_verts

    def check_foldability(self, new_vertices):  # sv_faces: list):
        # === triangle inequality check if non optimize selected
        if np.all(~np.array(self.env.triangle_inequality_holds)) or (not self.env.optimize_psi and \
            not np.all(self.env.triangle_inequality_holds)):
            return False, "Triangle Inequality does not hold: U_max > U_min + U_med"

        # === global intersection test: triangle-triangle-intersection
        if self.tritri_isec_check(new_vertices):  #sv_faces):
            return False, "intersecting faces"
        else:
            return True, "all tests passed"

    @staticmethod
    def point_in_triangle(P, triangle):
        A, B, C = triangle
        v0 = [C[0] - A[0], C[1] - A[1]]
        v1 = [B[0] - A[0], B[1] - A[1]]
        v2 = [P[0] - A[0], P[1] - A[1]]
        cross = lambda u, v: u[0] * v[1] - u[1] * v[0]
        u = cross(v2, v0)
        v = cross(v1, v2)
        d = cross(v1, v0)
        if d < 0:
            u, v, d = -u, -v, -d
        return u > 0 and v > 0 and (u + v) < d

    def tritri_isec_check(self, new_vertices):  #sv_faces=[]):
        # === triangle-triangle intersection test
        max_fold_angle_index = np.min(np.where(self.env.triangle_inequality_holds))
        all_3D_points = self.env.all_3D_points.swapaxes(0,1)
        points_2D = np.asarray(self.env.points_2D)
        for idx in range(len(all_3D_points)-1, max_fold_angle_index-1, -1):
            points = all_3D_points[idx]
            for face in self.env.triangles:
                for new_face in self.new_faces:
                    if self.tri_check(face, new_face, points[face], points[new_face]):
                        if idx == len(all_3D_points)-1 or not self.env.optimize_psi:
                            return True
                        for non_foldable_idx in range(idx, max_fold_angle_index-1, -1):
                            self.env.triangle_inequality_holds[non_foldable_idx] = False
                        return False
        return False

    def tri_check(self,f_a,f_b,f_a_arr,f_b_arr):
        f_a_arr = f_a_arr.reshape((3,3))
        f_b_arr = f_b_arr.reshape((3,3))
        if sum([a==b for a in f_a for b in f_b])>=2:
            return False # adjacenct or equal
        else:
            return NoDivTriTriIsect(
                    f_a_arr[0,:],f_a_arr[1,:],f_a_arr[2,:],  # face a vertices
                    f_b_arr[0,:],f_b_arr[1,:],f_b_arr[2,:])   # face b vertices

    def get_final_transform(self):
        vec_arr = np.array(self.env.points_2D)[self.surrounding_vertices]-np.array(self.coords)
        surr_vecs = np.hstack((vec_arr,np.zeros(len(self.surrounding_vertices)).reshape(-1,1)))
        surr_vecs_1 = np.roll(surr_vecs,-1,axis=0)
        # === compute sector angles for first unit
        sec_angles = np.array(planar_angle(surr_vecs,surr_vecs_1))[:-1]
        alpha_arr = np.stack((sec_angles,)*len(self.env.psi_opt),axis=0)
        # === collect dihedral angles from vertex to be extended
        rho_arr = self.dihedral_angles.copy()[:,:-1]
        # === resulting first unit
        final_transform = []
        reverse_orient = Rz(np.pi)
        s = np.roll(np.array(alpha_arr),-1)
        d = np.roll(rho_arr,-1)
        d = np.insert(d[:,:-1],0,0,axis=1)
        for i in range(len(self.env.psi_opt)):
            Mffw = Rz(0)
            for a,r in zip(alpha_arr[i],rho_arr[i]):
                Mffw = Mffw.dot(Rx(r).dot(Rz(a)))
            new_rot = self.init_rot[i].dot(Mffw)
            final_transform.append(new_rot)
        return final_transform


import pygame
import random
import display_answers
import chemistry_set

#Clase auxiliar de display_chemistry_problems para mostrar los textos de los problemas de quimica
class ScreenText:
    # La función con la que se instancia el objeto
    def __init__(self, size, screen):
        self.size = size
        self.screen = screen
    # La función que inicializa los textos y manda llamar el diccionario con los mismos,funcion que se llama solo 1 vez
    def init_var(self):
        self.data_questions=chemistry_set.element_variables()

        element_font = pygame.font.Font('assets/Diagramm-Regular.ttf', ((self.size//100)*45)//2)
        self.element_symbol_text = element_font.render(str(self.data_questions[0]), True, (0, 0, 0), (255, 255, 255))
        self.element_symbol_textRect = self.element_symbol_text.get_rect()
        self.element_symbol_textRect.center = (self.size // 2, self.size // 2 - (self.size // 10))

        element_font = pygame.font.Font('assets/Diagramm-Regular.ttf', ((self.size//100)*45)//6)
        self.element_number_text = element_font.render(str(self.data_questions[1]), True, (0, 0, 0), (255, 255, 255))
        self.element_number_textRect = self.element_number_text.get_rect()
        self.element_number_textRect.center = ((self.size // 2 - ((self.size//100)*45) // 2)
                                               +self.size//13, ((self.size // 2 - ((self.size//100)*45) // 2)
                                                                - (self.size / 10))+self.size//13)
        element_font = pygame.font.Font('assets/Diagramm-Regular.ttf', ((self.size//100)*45)//6)
        self.element_name_text = element_font.render('?', True, (0, 0, 0), (255, 255, 255))
        self.element_name_textRect = self.element_name_text.get_rect()
        self.element_name_textRect.center = (self.size//2, self.size // 2 + (((self.size//100)*45) // 10))

        self.data_questions.pop(0)
        self.data_questions.pop(0)
        self.answer_text=display_answers.AnswersDisplay(self.size,self.screen,self.data_questions)
        self.answer_text.init_var()

    # Una función que esta en un ciclo mostrando los elementos
    def show(self):
        self.answer_text.show()
        self.screen.blit(self.element_symbol_text, self.element_symbol_textRect)
        self.screen.blit(self.element_number_text, self.element_number_textRect)
        self.screen.blit(self.element_name_text, self.element_name_textRect)


import os

import stripe
from django.http import JsonResponse
from django.shortcuts import render
from django.views import View
from dotenv import load_dotenv

from .models import Item

load_dotenv()

stripe.api_key = os.getenv('SEC_KEY')

class CreateCheckoutSessionView(View):
    """
    Gets the ID of the Stripe session used for payment for the item chosen.
    Invokes the Stripe checkout session by sending data related to the item.
    """
    def post(self, request, *args, **kwargs):
        item_id = self.kwargs['pk']
        item = Item.objects.get(id=item_id)
        DOMAIN = r'http://127.0.0.1:8000'
        # DOMAIN = r'http://cdcollectionsale.site'
        checkout_session = stripe.checkout.Session.create(
            payment_method_types=['card'],
            line_items=[
                {
                    'price_data': {
                        'currency': 'rub',
                        'unit_amount': item.price,
                        'product_data': {
                            'name': item.name
                        },
                    },
                    'quantity': 1,
                },
            ],
            metadata={
                'item_id': item.id
            },
            mode='payment',
            success_url=DOMAIN + '/thanks/',
            cancel_url=DOMAIN + '/index/'
        )
        return JsonResponse({
            'id': checkout_session.id
        })

def item_details(request, pk):
    """
    Displays an individual instance of the model Item.
    """
    item = Item.objects.get(pk=pk)
    context = {
        'item': item,
        'STRIPE_PUBLIC_KEY': os.getenv('PUB_KEY')
    }
    return render(request, 'main/item_details.html', context)

def index(request):
    """
    Displays a list of the model Item instances.
    """
    items = Item.objects.all()
    return render(request, 'main/items_list.html', {'items': items})

def thanks(request):
    """
    Displays text after successful payment.
    """
    return render(request, 'main/thanks.html')


from django.urls import reverse

from feedbacks.model_form import FeedbackModelForm
from feedbacks.models import Feedback

def test_feedbacks_page(client, login_user, feedback_factory, faker):
    feedback = feedback_factory()
    url = reverse("feedbacks")

    # Open page as unregistered user
    response = client.get(url, follow=True)
    assert response.status_code == 200
    assert any(i[0] == reverse("login") + f"?next={url}" for i in response.redirect_chain)

    # Open page as registered user
    client, user = login_user
    response = client.get(url)
    assert response.status_code == 200
    assert type(response.context["form"]) == FeedbackModelForm
    assert feedback in response.context["page_obj"].object_list

    # Post incorrect data: empty data
    assert Feedback.objects.all().count() == 1
    response = client.post(url, data={})
    assert response.status_code == 200
    assert response.context["form"].errors["text"]
    assert response.context["form"].errors["user"]
    assert response.context["form"].errors["rating"]
    assert Feedback.objects.all().count() == 1

    # Post incorrect data: wrong user id
    data = {
        "text": faker.sentence(),
        "user": faker.uuid4(),
        "rating": 3
    }
    response = client.post(url, data=data)
    assert response.status_code == 200
    assert response.context["form"].errors["user"]
    assert Feedback.objects.all().count() == 1

    # Post incorrect data: wrong rating type
    data = {
        "text": faker.sentence(),
        "user": str(user.id),
        "rating": faker.word()
    }
    response = client.post(url, data=data)
    assert response.status_code == 200
    assert response.context["form"].errors["rating"]
    assert Feedback.objects.all().count() == 1

    # Post incorrect data: wrong rating (>5)
    data = {
        "text": faker.sentence(),
        "user": str(user.id),
        "rating": 10
    }
    response = client.post(url, data=data)
    assert response.status_code == 200
    assert response.context["form"].errors["rating"]
    assert Feedback.objects.all().count() == 1

    # Post incorrect data: wrong rating (<0)
    data = {
        "text": faker.sentence(),
        "user": str(user.id),
        "rating": -5
    }
    response = client.post(url, data=data)
    assert response.status_code == 200
    assert response.context["form"].errors["rating"]
    assert Feedback.objects.all().count() == 1

    # Post incorrect data: wrong rating (=0)
    data = {
        "text": faker.sentence(),
        "user": str(user.id),
        "rating": 0
    }
    response = client.post(url, data=data)
    assert response.status_code == 200
    assert response.context["form"].errors["rating"]
    assert Feedback.objects.all().count() == 1

    # Post correct data into form; new object have to be displayed
    text = faker.sentence()
    data = {
        "text": text,
        "user": str(user.id),
        "rating": faker.pyint(min_value=1, max_value=5)
    }
    response = client.post(url, data=data)
    assert response.status_code == 200
    assert Feedback.objects.all().count() == 2
    assert Feedback.objects.filter(
        text=data["text"],
        user=data["user"],
        rating=data["rating"]
    ).exists()
    assert len(response.context["page_obj"].object_list) == 2

    # Post correct data into form; symbols have to be excluded from the text
    symbols = "&%$#@"
    raw_text = faker.sentence()
    text = raw_text + symbols
    data = {
        "text": text,
        "user": str(user.id),
        "rating": faker.pyint(min_value=1, max_value=5)
    }
    response = client.post(url, data=data)
    assert response.status_code == 200
    assert Feedback.objects.filter(text=raw_text).exists()
    feedback = Feedback.objects.get(text=raw_text)
    assert symbols not in feedback.text


#!/usr/bin/env python
"""Simple A* Example script

Filename: search.py
Author: James Casey
Date Created: 2019-12-02
Last Updated: 2019-12-03
"""

import click
import logging
import structlog
from structlog.stdlib import LoggerFactory
import pygame
import random
from enum import Enum
from pdb import set_trace

structlog.configure(logger_factory=LoggerFactory())
log = structlog.get_logger()

debug = log.debug
info = log.info
warning = log.warning
error = log.error

# Global stuff to make life easier
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
CYAN = (0, 255, 255)
YELLOW = (255,255,0)

WIDTH=800
HEIGHT=600
SQUARE_SIZE = 40
MAX_X = int(WIDTH / SQUARE_SIZE) - 1
MAX_Y = int(HEIGHT / SQUARE_SIZE) - 1

def square_center(square):
    """ Get the center of a given square. """

    x = square[0]*SQUARE_SIZE + 1 + SQUARE_SIZE / 2
    y = square[1]*SQUARE_SIZE + 1 + SQUARE_SIZE / 2

    return (x,y)

def get_neighbors(square, clicked_squares=[], plus_only=False):
    """ Get a list of the neighbors for a square. """

    neighbors = []

    # Loop over the possible x positions
    for i in [square[0] - 1, square[0], square[0] + 1]:

        # make sure we stay in our region
        if i < 0 or i > MAX_X:
            continue

        # Loop over the possible y positions
        for j in [square[1] - 1, square[1], square[1] + 1]:

            # make sure we stay in our region
            if j < 0 or j > MAX_Y:
                continue

            # skip the given square
            if i == square[0] and j == square[1]:
                continue

            # Include/Exclude the diagonal paths
            if plus_only is True:
                if  i == square[0] - 1 and j !=  square[1]:
                    continue
                if  i == square[0] + 1 and j !=  square[1]:
                    continue

            # Deal with barriers
            if [i,j] in clicked_squares:
                continue

            neighbors.append([i,j])

    return neighbors

class PathNode:
    """ Store the path square information. """

    def __init__(self, parent=None, pos=None, start_square=None, end_square=None):

        self.parent_node = parent
        self.pos = pos
        self.start_square = start_square
        self.end_square = end_square

        self.f = 0
        self.g = 0
        self.h = 0

        self.set_h()

    def set_h(self):
        """ Simple h generator. """

        self.h = ((self.end_square[0] - self.pos[0])
                  + (self.end_square[1] - self.pos[1]))

    def __repr__(self):
        return f"<PathNode: {self.pos}>"

def find_path(start_square, end_square, clicked_squares, plus_only=False):

    # initial set up
    open_list = []
    closed_list = []

    open_list.append(PathNode(parent=None,
                              pos=start_square,
                              start_square=start_square,
                              end_square=end_square))

    # Run until we've found the path
    searching = True
    while searching:

        # Stop when we get have explored all paths
        if len(open_list) == 0:
            break

        # Sort the path nodes to find the shortest so far
        open_list = sorted(open_list, key=lambda entry: -entry.g)
        q = open_list.pop()

        # loop over all the neighbors and update the path information
        for neighbor in get_neighbors(q.pos, clicked_squares, plus_only=plus_only):

            node = PathNode(parent=q,
                            pos = neighbor,
                            start_square=start_square,
                            end_square=end_square)
            node.g = q.g + 1
            node.f = node.g + node.h

            # Stop searching when we get to the end
            if neighbor == end_square:
                searching = False
                break

            # check to see if we already have the node in the open list with
            # a better f value
            check_open = False
            for open_node in open_list:
                if node.pos == open_node.pos and open_node.f <= node.f:
                    check_open = True
                    break
            if check_open is True:
                continue

            # check to see if we already have the node in the closed list with
            # a better f value
            check_closed = False
            for closed_node in closed_list:
                if node.pos == closed_node.pos and closed_node.f <= node.f:
                    check_closed = True
                    continue
            if check_closed is True:
                continue

            # if we make it this far, add the neighbor node to the open list
            open_list.append(node)

        # add the node to the closed list
        closed_list.append(q)

    # open_list = sorted(open_list, key=lambda entry: -entry.g)
    last = node

    # build the path backwards from finish to start
    best_path = []
    while True:
        if last.parent_node is None:
            break
        best_path.append(last.pos)
        last = last.parent_node
    return best_path

@click.command()
@click.option("-n", "--draw-neighbors", is_flag=True, default=False,
                help="Draw neighbors on click")
@click.option("-p", "--plus-only", is_flag=True, default=False,
                help="Set neighbors to only up/down and left/right")
@click.option("-v", "--verbose", is_flag=True, default=False,
              help="Show debuggging information")
def main(verbose, plus_only, draw_neighbors):

    if verbose is True:
        logging.basicConfig(level=logging.DEBUG)
    else:
        logging.basicConfig(level=logging.WARNING)

    # initialize everything
    pygame.init()
    pygame.font.init()

    gDisplay = pygame.display.set_mode((WIDTH,HEIGHT))
    clock = pygame.time.Clock()

    start_square = [1,1]
    end_square = [MAX_X-1,MAX_Y-1]
    clicked_squares = []
    path_squares = []
    neighbors = []

    running = True
    while running:

        # Check for interaction
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False

            # Mouse interactions here
            if event.type == pygame.MOUSEBUTTONDOWN:

                # Add/Remove a barrier
                if pygame.mouse.get_pressed() == (1,0,0):
                    pos = pygame.mouse.get_pos()
                    x = pos[0]
                    y = pos[1]
                    new_square = [int(x/SQUARE_SIZE),int(y/SQUARE_SIZE)]

                    # Draw neighbors of the clicked square as well
                    # this is mostly for testing purposes
                    if draw_neighbors is True:
                        neighbors = get_neighbors(new_square,
                                plus_only=plus_only)

                    # Don't do anything to the start/end squares
                    if new_square == start_square or new_square == end_square:
                        continue

                    # toggle the barrier on or off
                    if new_square in clicked_squares:
                        clicked_squares.remove(new_square)
                    else:
                        clicked_squares.append(new_square)

                # Run the search
                elif pygame.mouse.get_pressed() == (0,0,1):
                    path_squares = find_path(start_square, end_square,
                            clicked_squares, plus_only)
                    neighbors = []

        gDisplay.fill(BLACK)

        # Draw the grid
        for i in range(1,int(WIDTH/SQUARE_SIZE)):
            x = SQUARE_SIZE*i
            pygame.draw.line(gDisplay, WHITE, (x,0), (x,HEIGHT),1)

        for i in range(1,int(HEIGHT/SQUARE_SIZE)):
            y = SQUARE_SIZE*i
            pygame.draw.line(gDisplay, WHITE, (0,y), (WIDTH,y),1)

        # Draw best path
        if path_squares is not None:
            last_square = start_square
            for square in path_squares[::-1]:
                x = square[0]*SQUARE_SIZE + 1
                y = square[1]*SQUARE_SIZE + 1
                pygame.draw.rect(gDisplay, YELLOW,
                        pygame.Rect(x,y,SQUARE_SIZE - 1, SQUARE_SIZE - 1))
                pygame.draw.line(gDisplay, RED,
                        (square_center(last_square)),
                        (square_center(square)), 2)
                last_square = square

        # Draw neighbors of clicked squares (if enabled)
        for square in neighbors:
            x = square[0]*SQUARE_SIZE + 1
            y = square[1]*SQUARE_SIZE + 1
            pygame.draw.rect(gDisplay, CYAN, pygame.Rect(x,y,SQUARE_SIZE - 1,
                SQUARE_SIZE - 1))

        # Draw clicked squares
        for square in clicked_squares:
            x = square[0]*SQUARE_SIZE + 1
            y = square[1]*SQUARE_SIZE + 1
            pygame.draw.rect(gDisplay, BLUE, pygame.Rect(x,y,SQUARE_SIZE - 1,
                SQUARE_SIZE - 1))

        # Draw Start Square
        x = start_square[0]*SQUARE_SIZE + 1
        y = start_square[1]*SQUARE_SIZE + 1
        pygame.draw.rect(gDisplay, GREEN, pygame.Rect(x,y,SQUARE_SIZE - 1,
            SQUARE_SIZE - 1))

        # Draw End Square
        x = end_square[0]*SQUARE_SIZE + 1
        y = end_square[1]*SQUARE_SIZE + 1
        pygame.draw.rect(gDisplay, RED, pygame.Rect(x,y,SQUARE_SIZE - 1,
            SQUARE_SIZE - 1))

        pygame.display.update()
        clock.tick(30)

if __name__ == "__main__":
    main()


from classes.repository.conectable_mixin import ConnectableMixin
from classes.entity.domain import Domain
from datetime import datetime

class DomainRepository(ConnectableMixin):

    def __init__(self):
        super().__init__()

    def save(self, domain:Domain) -> Domain:
        SQL = """
        INSERT INTO domains (description, deleted_at) VALUES (?, ?)
        """
        domain.id = self.execute_last_row_id(SQL, (domain.description,None))
        if domain.id:
            return domain
        else:
            return None

    def update(self, domain:Domain) -> Domain:
        SQL = """
        UPDATE
            domains
        SET
            description = ?
        WHERE
            id = ? AND deleted_at is null
        """
        affectedRows = self.execute(SQL, (domain.description, domain.id))
        if affectedRows > 0:
            return domain
        else:
            return None

    def delete(self, domain:Domain) -> bool:
        SQL = """
        UPDATE
            domains
        SET
            deleted_at = ?
        WHERE
            id = ?
        """
        return self.execute(SQL, (datetime.now(), domain.id)) == 1

    def fetch(self, id:int) -> Domain:
        SQL = """
        SELECT
            id,
            description
        FROM
            domains
        WHERE
            id = ? and deleted_at is null
        """

        fetched = self.fetch_one(SQL, (id,))
        if fetched:
            return Domain(id=fetched[0], description=fetched[1])
        else:
            return None


import os
import cv2
import face_recognition
import numpy as np
from tqdm import tqdm
from collections import defaultdict
from imutils.video import VideoStream
from eye_status import *

def init():
    face_cascPath = 'haarcascade_frontalface_alt.xml'
    # face_cascPath = 'lbpcascade_frontalface.xml'

    open_eye_cascPath = 'haarcascade_eye_tree_eyeglasses.xml'
    left_eye_cascPath = 'haarcascade_lefteye_2splits.xml'
    right_eye_cascPath ='haarcascade_righteye_2splits.xml'
    dataset = 'faces'

    face_detector = cv2.CascadeClassifier(face_cascPath)
    open_eyes_detector = cv2.CascadeClassifier(open_eye_cascPath)
    left_eye_detector = cv2.CascadeClassifier(left_eye_cascPath)
    right_eye_detector = cv2.CascadeClassifier(right_eye_cascPath)

    print("[LOG] Opening webcam ...")
    video_capture = VideoStream(src=0).start()

    model = load_model()

    print("[LOG] Collecting images ...")
    images = []
    for direc, _, files in tqdm(os.walk(dataset)):
        for file in files:
            if file.endswith("jpg"):
                images.append(os.path.join(direc,file))
    return (model,face_detector, open_eyes_detector, left_eye_detector,right_eye_detector, video_capture, images)

def process_and_encode(images):
    # initialize the list of known encodings and known names
    known_encodings = []
    known_names = []
    print("[LOG] Encoding faces ...")

    for image_path in tqdm(images):
        # Load image
        image = cv2.imread(image_path)
        # Convert it from BGR to RGB
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

        # detect face in the image and get its location (square boxes coordinates)
        boxes = face_recognition.face_locations(image, model='hog')

        # Encode the face into a 128-d embeddings vector
        encoding = face_recognition.face_encodings(image, boxes)

        # the person's name is the name of the folder where the image comes from
        name = image_path.split(os.path.sep)[-2]

        if len(encoding) > 0 :
            known_encodings.append(encoding[0])
            known_names.append(name)

    return {"encodings": known_encodings, "names": known_names}

def isBlinking(history, maxFrames):
    """ @history: A string containing the history of eyes status
         where a '1' means that the eyes were closed and '0' open.
        @maxFrames: The maximal number of successive frames where an eye is closed """
    for i in range(maxFrames):
        pattern = '1' + '0'*(i+1) + '1'
        if pattern in history:
            return True
    return False

def detect_and_display(model, video_capture, face_detector, open_eyes_detector, left_eye_detector, right_eye_detector, data, eyes_detected):
        frame = video_capture.read()
        # resize the frame
        frame = cv2.resize(frame, (0, 0), fx=0.6, fy=0.6)

        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

        # Detect faces
        faces = face_detector.detectMultiScale(
            gray,
            scaleFactor=1.2,
            minNeighbors=5,
            minSize=(50, 50),
            flags=cv2.CASCADE_SCALE_IMAGE
        )

        # for each detected face
        for (x,y,w,h) in faces:
            # Encode the face into a 128-d embeddings vector
            encoding = face_recognition.face_encodings(rgb, [(y, x+w, y+h, x)])[0]

            # Compare the vector with all known faces encodings
            matches = face_recognition.compare_faces(data["encodings"], encoding)

            # For now we don't know the person name
            name = "Unknown"

            # If there is at least one match:
            if True in matches:
                matchedIdxs = [i for (i, b) in enumerate(matches) if b]
                counts = {}
                for i in matchedIdxs:
                    name = data["names"][i]
                    counts[name] = counts.get(name, 0) + 1

                # determine the recognized face with the largest number of votes
                name = max(counts, key=counts.get)

            face = frame[y:y+h,x:x+w]
            gray_face = gray[y:y+h,x:x+w]

            eyes = []

            # Eyes detection
            # check first if eyes are open (with glasses taking into account)
            open_eyes_glasses = open_eyes_detector.detectMultiScale(
                gray_face,
                scaleFactor=1.1,
                minNeighbors=5,
                minSize=(30, 30),
                flags = cv2.CASCADE_SCALE_IMAGE
            )
            # if open_eyes_glasses detect eyes then they are open
            if len(open_eyes_glasses) == 2:
                eyes_detected[name]+='1'
                for (ex,ey,ew,eh) in open_eyes_glasses:
                    cv2.rectangle(face,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

            # otherwise try detecting eyes using left and right_eye_detector
            # which can detect open and closed eyes
            else:
                # separate the face into left and right sides
                left_face = frame[y:y+h, x+int(w/2):x+w]
                left_face_gray = gray[y:y+h, x+int(w/2):x+w]

                right_face = frame[y:y+h, x:x+int(w/2)]
                right_face_gray = gray[y:y+h, x:x+int(w/2)]

                # Detect the left eye
                left_eye = left_eye_detector.detectMultiScale(
                    left_face_gray,
                    scaleFactor=1.1,
                    minNeighbors=5,
                    minSize=(30, 30),
                    flags = cv2.CASCADE_SCALE_IMAGE
                )

                # Detect the right eye
                right_eye = right_eye_detector.detectMultiScale(
                    right_face_gray,
                    scaleFactor=1.1,
                    minNeighbors=5,
                    minSize=(30, 30),
                    flags = cv2.CASCADE_SCALE_IMAGE
                )

                eye_status = '1' # we suppose the eyes are open

                # For each eye check wether the eye is closed.
                # If one is closed we conclude the eyes are closed
                for (ex,ey,ew,eh) in right_eye:
                    color = (0,255,0)
                    pred = predict(right_face[ey:ey+eh,ex:ex+ew],model)
                    if pred == 'closed':
                        eye_status='0'
                        color = (0,0,255)
                    cv2.rectangle(right_face,(ex,ey),(ex+ew,ey+eh),color,2)
                for (ex,ey,ew,eh) in left_eye:
                    color = (0,255,0)
                    pred = predict(left_face[ey:ey+eh,ex:ex+ew],model)
                    if pred == 'closed':
                        eye_status='0'
                        color = (0,0,255)
                    cv2.rectangle(left_face,(ex,ey),(ex+ew,ey+eh),color,2)
                eyes_detected[name] += eye_status

            # Each time, we check if the person has blinked
            # If yes, we display its name
            if isBlinking(eyes_detected[name],3):
                cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
                # Display name
                y = y - 15 if y - 15 > 15 else y + 15
                cv2.putText(frame, name, (x, y), cv2.FONT_HERSHEY_SIMPLEX,0.75, (0, 255, 0), 2)

        return frame

if __name__ == "__main__":
    (model, face_detector, open_eyes_detector,left_eye_detector,right_eye_detector, video_capture, images) = init()
    data = process_and_encode(images)

    eyes_detected = defaultdict(str)
    while True:
        frame = detect_and_display(model, video_capture, face_detector, open_eyes_detector,left_eye_detector,right_eye_detector, data, eyes_detected)
        cv2.imshow("Face Liveness Detector", frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cv2.destroyAllWindows()
    video_capture.stop()


import re

new = input('Enter new version number: ')

def change(path, regex, replacement):
    with open(path, 'r') as fl:
        data = fl.read()
    with open(path, 'w') as fl:
        fl.write(re.sub(regex, replacement, data))

# update VERSION tracker file at root
with open( 'VERSION', 'w') as fl:
    fl.write(new)

# update index.html template
change(
    'django_smg/frontend/templates/frontend/index.html',
    r'webpack_output/main_v(.*)\.js',
    f'webpack_output/main_v{new}.js',
)

# update package.json
change(
    'django_smg/frontend/package.json',
    r'"version": "(.*)",',
    f'"version": "{new}",'
)

# update webpack config
change(
    'django_smg/frontend/webpack.config.js',
    r'filename: "main_v(.*).js",',
    f'filename: "main_v{new}.js",',
)


from flask_restful import Resource
from services.jsondb import JsonDb

class FlatFileResource(Resource):

  def get(self, file_id=None):
    db = JsonDb()
    try:
      file_descriptor = db.get_by_key(file_id)
      return file_descriptor
    except:
      return {
        'error': 'FILE_NOT_FOUND',
        'message': 'File {0} not found'.format(file_id)
      }, 404


import numpy as np

import torch

def nms(bbox, thresh, score=None, limit=None):
    """Suppress bounding boxes according to their IoUs and confidence scores.
    Args:
        bbox (array): Bounding boxes to be transformed. The shape is
            :math:`(R, 4)`. :math:`R` is the number of bounding boxes.
        thresh (float): Threshold of IoUs.
        score (array): An array of confidences whose shape is :math:`(R,)`.
        limit (int): The upper bound of the number of the output bounding
            boxes. If it is not specified, this method selects as many
            bounding boxes as possible.
    Returns:
        array:
        An array with indices of bounding boxes that are selected. \
        They are sorted by the scores of bounding boxes in descending \
        order. \
        The shape of this array is :math:`(K,)` and its dtype is\
        :obj:`numpy.int32`. Note that :math:`K \\leq R`.

    from: https://github.com/chainer/chainercv
    """

    if len(bbox) == 0:
        return np.zeros((0,), dtype=np.int32)

    if score is not None:
        order = score.argsort()[::-1]
        bbox = bbox[order]
    bbox_area = np.prod(bbox[:, 2:] - bbox[:, :2], axis=1)

    selec = np.zeros(bbox.shape[0], dtype=bool)
    for i, b in enumerate(bbox):
        tl = np.maximum(b[:2], bbox[selec, :2])
        br = np.minimum(b[2:], bbox[selec, 2:])
        area = np.prod(br - tl, axis=1) * (tl < br).all(axis=1)

        iou = area / (bbox_area[i] + bbox_area[selec] - area)
        if (iou >= thresh).any():
            continue

        selec[i] = True
        if limit is not None and np.count_nonzero(selec) >= limit:
            break

    selec = np.where(selec)[0]
    if score is not None:
        selec = order[selec]
    return selec.astype(np.int32)

def postprocess(prediction, num_classes, conf_thre=0.7, nms_thre=0.45):
    """
    Postprocess for the output of YOLO model
    perform box transformation, specify the class for each detection,
    and perform class-wise non-maximum suppression.
    Args:
        prediction (torch tensor): The shape is :math:`(N, B, 4)`.
            :math:`N` is the number of predictions,
            :math:`B` the number of boxes. The last axis consists of
            :math:`xc, yc, w, h` where `xc` and `yc` represent a center
            of a bounding box.
        num_classes (int):
            number of dataset classes.
        conf_thre (float):
            confidence threshold ranging from 0 to 1,
            which is defined in the config file.
        nms_thre (float):
            IoU threshold of non-max suppression ranging from 0 to 1.

    Returns:
        output (list of torch tensor):

    """
    box_corner = prediction.new(prediction.shape)
    box_corner[:, :, 0] = prediction[:, :, 0] - prediction[:, :, 2] / 2
    box_corner[:, :, 1] = prediction[:, :, 1] - prediction[:, :, 3] / 2
    box_corner[:, :, 2] = prediction[:, :, 0] + prediction[:, :, 2] / 2
    box_corner[:, :, 3] = prediction[:, :, 1] + prediction[:, :, 3] / 2
    prediction[:, :, :4] = box_corner[:, :, :4]

    output = [None for _ in range(len(prediction))]
    for i, image_pred in enumerate(prediction):
        # Filter out confidence scores below threshold
        # class_pred = torch.max(image_pred[:, 5:5 + num_classes], 1)
        # class_pred = class_pred[0]
        conf_mask = (image_pred[:, 4]  >= conf_thre).squeeze()
        image_pred = image_pred[conf_mask]

        # If none are remaining => process next image
        if not image_pred.size(0):
            continue
        # Get detections with higher confidence scores than the threshold
        ind = (image_pred[:, 5:] * image_pred[:, 4][:, None] >= conf_thre).nonzero()
        # Detections ordered as (x1, y1, x2, y2, obj_conf, class_conf, class_pred)
        detections = torch.cat((
                image_pred[ind[:, 0], :5],
                image_pred[ind[:, 0], 5 + ind[:, 1]].unsqueeze(1),
                ind[:, 1].float().unsqueeze(1)
                ), 1)
        # Iterate through all predicted classes
        unique_labels = detections[:, -1].cpu().unique()
        if prediction.is_cuda:
            unique_labels = unique_labels.cuda()
        for c in unique_labels:
            # Get the detections with the particular class
            detections_class = detections[detections[:, -1] == c]
            nms_in = detections_class.cpu().numpy()
            nms_out_index = nms(
                nms_in[:, :4], nms_thre, score=nms_in[:, 4]*nms_in[:, 5])
            detections_class = detections_class[nms_out_index]
            if output[i] is None:
                output[i] = detections_class
            else:
                output[i] = torch.cat((output[i], detections_class))

    return output


# 반복문
def selectionSort(arr, s):
    n = len(arr)

    for i in range(0, n - 1):  # 마지막 2개 남았을 때는 0부터 n-2까지
        minI = i               # 맨 앞자리를 제일 작은 숫자라고 가정

        # 남은 자리와 비교
        for j in range(i + 1, n):  # i의 오른쪽 숫자들 중에 가장 작은 값을 가지는 인덱스를 i와 바꾼다
            if arr[j] < arr[minI]:
                minI = j           # 최솟값을 작은 값의 인덱스로 바꾼다

        # 가장 작은 값을 현재 비교하는 인덱스 값과 바꾼다
        arr[minI], arr[i] = arr[i], arr[minI]

arr = [2, 4, 6, 1, 9, 8, 7, 0]
selectionSort(arr, 0)
print(arr)


from selenium import webdriver
from selenium.webdriver.support.ui import Select
import pprint as pp
import pandas as pd

def scrape_table(table):
	table_rows = table.find_elements_by_tag_name('tr')
	data = [scrape_row(row) for row in table_rows]
	return(data)

def scrape_row(row):
	attrs = row.find_elements_by_tag_name('td')
	data = [attr.text for attr in attrs]
	return(data)

def find_symbol(team_name):
	#(team_name)
	indx = symbols['teamName'].str.contains(team_name)
	print('{} :::: {}'.format(team_name,symbols.loc[indx,'teamName']))
	try:
		return(symbols.loc[indx,'crestURI'].tolist()[0])
	except:
		return('Noneee')

symbols = pd.read_csv('symbols.csv',header=0)

driver = webdriver.Chrome()

# Pulling

LEAGUES = dict(zip(['laliga','serie-a','ligue-1','premier-league','bundesliga'],
				   ['La Liga','Serie A','Ligue 1','Premier League','Bundesliga']))
fin = []
for lg in LEAGUES.keys():
	driver.get('http://www.beinsports.com/us/{}/statistics'.format(lg))
	form = driver.find_elements_by_css_selector("form.ranking-category")[1]
	select = Select(form.find_element_by_tag_name('select'))
	select.select_by_visible_text('Assists')
	# Desired Stats
	pandas_header = ['Pos','Name','GP','Team','Stat']
	STATS = ['goals','assists','chances_created']
	STATS = dict(zip(STATS,['Goals','Assists','Ch. Created']))
	for st in STATS.keys():
		select.select_by_value(st)
		table = driver.find_element_by_css_selector('div.'+st)
		dff = pd.DataFrame(scrape_table(table)[1:],columns=pandas_header)
		dff['Statname'] = STATS[st]
		dff['League'] = LEAGUES[lg]
		dff['ABBR'] = 'FCB'
		dff['CREST'] = 'http://upload.wikimedia.org/wikipedia/de/d/de/Getafe_CF.svg'
		dff['Name'] = dff['Name'].str.split().str[-1]
		fin.append(dff)
datas = pd.concat(fin)
driver.close()

#datas = pd.read_csv('super_table5.csv',header=0)

## Applying Crests
datas['CREST'] = datas['Team'].apply(find_symbol)

## Reseting index
datas.reset_index(inplace=True,drop=True)

# Saving
datas.to_csv('super_table5.csv',index=False)