# Надо еще сделать масштабирование по результатам проверки вылезания за пределы поля. Но для этого надо будет
# переделывать всю логику программы. А я уже топчусь на месте. Когда разберусь с питоном больше,
# тогда и переделаю. Плюс надо будет изменить на работу с точками как с объектами и добавить обратную связь с
# пользователем (кнопки, масштабирование колесом, замедление/ускорение, паузу и перемотку назад/вперед). Возможно,
# перейти на другой модуль, чтобы интерфейс был лучше. Или нарисовать свой. Пока не умею, как.

import pygame, time, easygui
from copy import copy

pygame.init()

# offer user to choose resolution of the window
resolutions = {'640 × 480': [640, 480],
               '800 × 600': [800, 600],
               '1024 × 768': [1024, 768],
               '1280 × 1024': [1280, 1024],
               '1440 × 900': [1440, 900],
               '1680 × 1050': [1680, 1050],
               '1920 × 1080': [1920, 1080],
               '2560 × 1440': [2560, 1440]}
resolution_choice = easygui.choicebox("Please select resolution", choices = resolutions.keys(), preselect = 1)
resolution = resolution_x, resolution_y = resolutions[resolution_choice]
screen = pygame.display.set_mode(resolution)
screen.fill([255, 255, 255])

# resolution_x = resolution[0]
# resolution_y = resolution[1]

cell_size = 40
cell_size_work = copy(cell_size)

field0 = int(cell_size_work / 2)
step = cell_size_work
center_field_x = field0 + step * (int(resolution_x / step / 2) - 1)
center_field_y = field0 + step * (int(resolution_y / step / 2) - 1)
dot_radius = int((cell_size_work / 2) * 0.7)

# function to scale the field down
def scale():
    new_cell_size = int(resolution_x / (int(resolution_x / cell_size_work) + 2))
    return new_cell_size

# function to check a cell to change state
def check(x, y):
    dots = {"dot_top_left": [x - step, y - step],
            "dot_top_center": [x, y - step],
            "dot_top_right": [x + step, y - step],
            "dot_center_left": [x - step, y],
            "dot_center_right": [x + step, y],
            "dot_bottom_left": [x - step, y + step],
            "dot_bottom_center": [x, y + step],
            "dot_bottom_right": [x + step, y + step]}
    count = 0
    center = False
    future = ""
    if screen.get_at([x, y]) == (0, 0, 0, 255):
        center = True
    for value in dots.values():
        if screen.get_at(value) == (0, 0, 0, 255):
            count += 1
    if center and 2 <= count <= 3:
        future = "live"
    elif center and (count < 2 or count > 3):
        future = "die"
    elif not center and count == 3:
        future = "born"
    else:
        future = "nothing"
    return future

# function to check borders
def border_check():
    top_left_starting_point = field0 + step
    top_rignt_starting_point = top_left_starting_point + (step * (int(resolution_x / cell_size_work) - 3))
    bottom_left_starting_point = top_left_starting_point + (step * (int(resolution_y / cell_size_work) - 3))
    presence = False
    while not presence:
        for i in range(0, int(resolution_x / step - 3)):
            dot_place = [top_left_starting_point + i * step, top_left_starting_point]
            if screen.get_at(dot_place) == (0, 0, 0, 255):
                presence = True
                break
        for i in range(0, int(resolution_y / step - 3)):
            dot_place = [top_left_starting_point, top_left_starting_point + i * step]
            if screen.get_at(dot_place) == (0, 0, 0, 255):
                presence = True
                break
        for i in range(0, int(resolution_y / step - 3)):
            dot_place = [top_rignt_starting_point, field0 + step + i * step]
            if screen.get_at(dot_place) == (0, 0, 0, 255):
                presence = True
                break
        for i in range(0, int(resolution_x / step - 3)):
            dot_place = [field0 + step + i * step, bottom_left_starting_point]
            if screen.get_at(dot_place) == (0, 0, 0, 255):
                presence = True
                break
    return "yes" # temporary return, I'll think on it more.

# draw the field
for i in range(0, resolution_x, step):
    pygame.draw.lines(screen, [0, 0, 0], False, [[i, 0], [i, resolution_y]], 1)
    pygame.draw.lines(screen, [0, 0, 0], False, [[0, i], [resolution_x, i]], 1)

pygame.display.flip()

# dot0 = [center_field_x + step * 0, center_field_y + step * 0]
# dot1 = [center_field_x + step * 0, center_field_y - step * 1]
# dot2 = [center_field_x + step * 1, center_field_y - step * 1]
# dot3 = [center_field_x - step * 1, center_field_y + step * 0]
# dot4 = [center_field_x + step * 0, center_field_y + step * 1]
#
# r_pentomino = [dot0, dot1, dot2, dot3, dot4]
#
# for i in r_pentomino:
#     pygame.draw.circle(screen, [0, 0, 0], i, 15, 0)

dot1 = [field0 + step * 2, field0 + step * 1]
dot2 = [field0 + step * 3, field0 + step * 2]
dot3 = [field0 + step * 3, field0 + step * 3]
dot4 = [field0 + step * 2, field0 + step * 3]
dot5 = [field0 + step * 1, field0 + step * 3]
glider = [dot1, dot2, dot3, dot4, dot5]

for i in glider:
    pygame.draw.circle(screen, [0, 0, 0], i, dot_radius, 0)

pygame.display.flip()

time.sleep(1)
for k in range(20):
    born = []
    die = []
    time.sleep(0.1)
    starting_point = field0 + step
    for i in range(int(resolution_x / step - 2)):
        for j in range(int(resolution_y / step - 2)):
            dot_place = [starting_point + i * step, starting_point + j * step]
            result = check(*dot_place)
            if result == "born":
                born.append(dot_place)
            elif result == "die":
                die.append(dot_place)
    for i in born:
        pygame.draw.circle(screen, [0, 0, 0], i, dot_radius, 0)
    for i in die:
        pygame.draw.circle(screen, [255, 255, 255], i, dot_radius, 0)
    pygame.display.flip()

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
pygame.quit()


from typing import Tuple, Callable, Optional, TypeVar, cast, Dict

from ..model import Model
from ..config import registry
from ..types import Array2d
from ..util import get_width
from .noop import noop
from ..types import XY_XY_OutT

InT = TypeVar("InT", bound=Array2d)
OutT = TypeVar("OutT", bound=Array2d)

@registry.layers("concatenate.v1")
def concatenate(*layers: Model) -> Model[InT, XY_XY_OutT]:
    """Compose two or more models `f`, `g`, etc, such that their outputs are
    concatenated, i.e. `concatenate(f, g)(x)` computes `hstack(f(x), g(x))`.
    Also supports chaining more than 2 layers.
    """
    if not layers:
        return cast(Model[InT, XY_XY_OutT], noop())
    elif len(layers) == 1:
        return layers[0]
    elif layers[0]._func is forward:
        layers[0].layers.extend(layers[1:])
        return layers[0]

    # only add an nI dimension if each sub-layer has one
    dims: Dict[str, Optional[int]] = {"nO": None}
    if all(node.has_dim("nI") in [True, None] for node in layers):
        dims = {"nO": None, "nI": None}

    return Model(
        "|".join(layer.name for layer in layers),
        forward,
        init=init,
        dims=dims,
        layers=layers,
    )

def forward(model: Model[InT, OutT], X: InT, is_train: bool) -> Tuple[OutT, Callable]:
    Ys, callbacks = zip(*[layer(X, is_train=is_train) for layer in model.layers])
    if isinstance(Ys[0], list):
        return _list_forward(model, X, Ys, callbacks, is_train)
    else:
        return _array_forward(model, X, Ys, callbacks, is_train)

def _array_forward(
    model: Model[InT, OutT], X, Ys, callbacks, is_train: bool
) -> Tuple[OutT, Callable]:
    widths = [Y.shape[1] for Y in Ys]
    output = model.ops.xp.hstack(Ys)

    def backprop(d_output: OutT) -> InT:
        dY = model.ops.xp.ascontiguousarray(d_output[:, : widths[0]])
        dX = callbacks[0](dY)
        start = widths[0]
        for bwd, width in zip(callbacks[1:], widths[1:]):
            dY = model.ops.xp.ascontiguousarray(d_output[:, start : start + width])
            dX += bwd(dY)
            start += width
        return dX

    return output, backprop

def _list_forward(
    model: Model[InT, OutT], X, Ys, callbacks, is_train: bool
) -> Tuple[OutT, Callable]:
    lengths = model.ops.asarray1i([len(x) for x in X])
    Ys = [model.ops.xp.concatenate(Y, axis=0) for Y in Ys]
    widths = [Y.shape[1] for Y in Ys]
    output = model.ops.xp.hstack(Ys)
    output = model.ops.unflatten(output, lengths)

    def backprop(d_output: OutT) -> InT:
        d_output = model.ops.xp.concatenate(d_output, axis=0)
        dY = model.ops.as_contig(d_output[:, : widths[0]])
        # We want to generalize unflatten later.
        dY = model.ops.asarray(model.ops.unflatten(dY, lengths))  # type: ignore
        dX = callbacks[0](dY)
        start = widths[0]
        for bwd, width in zip(callbacks[1:], widths[1:]):
            dY = model.ops.as_contig(d_output[:, start : start + width])
            dY = model.ops.asarray(model.ops.unflatten(dY, lengths))  # type: ignore
            dX += bwd(dY)
            start += width
        return dX

    return output, backprop

def init(
    model: Model[InT, OutT], X: Optional[InT] = None, Y: Optional[OutT] = None
) -> Model[InT, OutT]:
    if X is not None:
        if model.has_dim("nI") is not False:
            model.set_dim("nI", get_width(X))
        for layer in model.layers:
            if layer.has_dim("nI") is not False:
                layer.set_dim("nI", get_width(X))
    for layer in model.layers:
        layer.initialize(X=X, Y=Y)
    if all([layer.has_dim("nO") for layer in model.layers]):
        model.set_dim("nO", sum(layer.get_dim("nO") for layer in model.layers))
    return model


#!/usr/bin/python

from __future__ import print_function
import sys
import tempfile
from subprocess import call

from kubernetes.client.rest import ApiException
import oc_common
import jobs_common

def main(argv):
    if len(argv)==0:
        print('No arguments passed. Please specify a namespace, name, and value of ci.openshift.io/jenkins-job annotation')
    elif len(argv)==3:
        process_config(argv[0], argv[1], argv[2])

def process_config(namespace, name, annotation_value=None):
    if annotation_value != "true":
        print("configmap {}/{} is not applicable to Jenkins".format(namespace, name))
        return

    core_instance = oc_common.connect_to_kube_core()

    try:
        config_map = core_instance.read_namespaced_config_map(name, namespace)
    except ApiException as e:
        print("Exception when calling CoreV1Api->read_namespaced_configmap: {}\n".format(e))
        exit(1)

    if len(config_map.data) != 1:
        print("Invalid config map {}/{}: more than one data key present\n".format(namespace, name))

    if 'job.yml' not in config_map.data:
        print("Invalid config map {}/{}: no 'job.yml' key present\n".format(namespace, name))

    tmp_job_file = tempfile.mkstemp()
    with open(tmp_job_file, "w") as jobfile:
        jobfile.write(config_map.data['job.yml'])

    call(["jenkins-jobs", "update", tmp_job_file])
    jobs_common.add_to_known_names(namespace, name)

if __name__ == "__main__":
    main(sys.argv[1:])


def permStr(s1,s2):
    if len(s1)>len(s2):
        return False
    perms = []
    perm = []
    cnt = {l:0 for l in s1}
    for l in s1:
        cnt[l]+=1
    def dfs():
        if len(perm)==len(s1):
            perms.append(perm[::])
            return
        for l in cnt:
            if cnt[l]>0:
                perm.append(l)
                cnt[l]-=1
                dfs()
                perm.pop()
                cnt[l]+=1
    dfs()
    print("perms:",perms)
    joinedperms = []
    for _ in perms:
        joinedperms.append("".join(_))
    print(joinedperms)
    for perm in joinedperms:
        l,r = 0,0+len(s1)
        while True and r<=len(s2):
            print("s2",s2[l:r])
            if perm == s2[l:r]:
                return True
            l+=1
            r+=1

    return False
print(permStr("trinitrophenylmethylnitramine","xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdcda"))


# https://blog.socialcops.com/engineering/machine-learning-python/
import logging

import pandas as pd
import time
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.tree import DecisionTreeClassifier

def preprocess_titanic_df(df):
    result = df.copy()
    label_encoder = LabelEncoder()
    result.sex = label_encoder.fit_transform(result.sex)
    result.embarked = label_encoder.fit_transform(result.embarked)
    result = result.drop(['name', 'ticket', 'home.dest'], axis=1)
    return result

if __name__ == '__main__':
    start_time = time.time()

    formatter = logging.Formatter('%(asctime)s : %(name)s :: %(levelname)s : %(message)s')
    logger = logging.getLogger('main')
    logger.setLevel(logging.DEBUG)
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(formatter)
    logger.addHandler(console_handler)
    console_handler.setLevel(logging.DEBUG)
    logger.debug('started')

    input_file = '../input/titanic3.xls'
    logger.debug('reading data from %s' % input_file)

    titanic_df = pd.read_excel(input_file, encoding='ISO-8859-1')
    logger.debug('data has shape %d x %d' % titanic_df.shape)
    logger.debug('data has columns %s' % titanic_df.columns.values)
    logger.debug('mean by passenger class: \n%s' % titanic_df.groupby('pclass').mean())
    logger.debug('survived mean: %.4f' % titanic_df['survived'].mean())

    partial_columns = ['body', 'cabin', 'boat']
    t0 = titanic_df.drop(partial_columns, axis=1)
    t0['home.dest'] = t0['home.dest'].fillna('NA')
    t0 = t0.dropna()
    processed_df = preprocess_titanic_df(t0)
    target_columns = ['embarked', 'pclass', 'survived', 'sex']
    for target_column in target_columns:
        X = processed_df.drop([target_column], axis=1).values
        y = processed_df[target_column].values
        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
        clf_dt = DecisionTreeClassifier(max_depth=10)

        clf_dt.fit(X_train, y_train)
        logger.debug('target: %s score: %.4f' % (target_column, clf_dt.score(X_test, y_test)))

    # instead try dropping all of the target columns and then predict each of them
    X = processed_df.drop(target_columns, axis=1).values
    for target_column in target_columns:
        y = processed_df[target_column].values
        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
        clf_dt = DecisionTreeClassifier(max_depth=10)

        clf_dt.fit(X_train, y_train)
        logger.debug('target: %s score: %.4f' % (target_column, clf_dt.score(X_test, y_test)))

    logger.debug('done')
    finish_time = time.time()
    elapsed_hours, elapsed_remainder = divmod(finish_time - start_time, 3600)
    elapsed_minutes, elapsed_seconds = divmod(elapsed_remainder, 60)
    logger.info('Time: {:0>2}:{:0>2}:{:05.2f}'.format(int(elapsed_hours), int(elapsed_minutes), elapsed_seconds))
    console_handler.close()
    logger.removeHandler(console_handler)


import io
import sys

_INPUT = """\
6
4
-WWW
L-DD
LD-W
LDW-
2
-D
D-
"""

sys.stdin = io.StringIO(_INPUT)
case_no=int(input())
for __ in range(case_no):
  N=int(input())
  A=[input() for _ in range(N)]
  ans='correct'
  for i in range(N):
    for j in range(N):
      if i==j: continue
      if A[i][j]=='W' and A[j][i]!='L': ans='incorrect'
      if A[i][j]=='L' and A[j][i]!='W': ans='incorrect'
      if A[i][j]=='D' and A[j][i]!='D': ans='incorrect'
  print(ans)


# -*- coding: UTF-8 -*-
import random
import pandas as pd
import re
import jieba
from collections import Counter  # 2-gram

choice = random.choice  # choice method return one of all

my_grammar = '''
	sentence=pronoun_phrase verb_phrase noun_phrase|noun_phrase verb_phrase noun_phrase
	noun_phrase=Article* Adj* noun
	Article*=Article|null
	verb_phrase=adverb verb
	pronoun_phrase=Adj* pronoun
	Adj*=null | Adj Adj*
	adverb=独自地|暗暗地|充满希望地|神伤地|勇敢滴
	pronoun=他|她|它|你|我
	noun=猫|狗|地球|花|自然|草地|女孩|妹子|数字|外星人|神仙|alphago|流星|国度|人|国家|电影|政权|旋律|情节
	verb=撒拉嘿着|喜欢|看着|想象着|感受着|倾听着|坐在|践踏着|鄙视着|破坏着|勾引着
	Adj=好看的|神秘的|空中的|难以预测的|美好的|稀奇古怪的|奇异的|被毁灭的|澎湃的|热血的
	Article=一个|一只|一群|一堆|很多|那个|这个|那些|这些
'''
comment_grammar = '''
	sentence=pronoun_phrase verb_phrase noun_phrase
	noun_phrase=adj noun
	verb_phrase=adv verb
	pronoun_phrase=我|你|他|她|它|独自|那个人|那些人|这些人|某些人
	adj=特别的|澎湃的|令人泪目的|热血的|激情的|糟糕的|丑陋的|虚伪的|拜金的|好的|好|垃圾的|美丽的|优雅的|国产的|国外的|低端的|高级的|知性的|大的
	adv=不喜欢|喜欢|懒得|可能|坐着|站着|绝对
	verb=看|听|说|瞧|评论|想|思考|考虑着|成为
	noun=电影院|垃圾|电影|影评人|好莱坞大片|作者|导演|影片|大片|成本|效果|特效
'''

def create_grammar(grammar_str, split='=', line_split='\n'):
	grammar = {}
	for line in grammar_str.split(line_split):
		if not line.strip():
			continue
		exp, stmt = line.split(split)
		grammar[exp.strip()] = [s.split() for s in stmt.split('|')]  # key of sentence generate
	return grammar

print(create_grammar(my_grammar), '\n')

def generate(gram, target):
	if target not in gram:
		return target
	expand = [generate(gram, t) for t in choice(gram[target])]
	return ''.join([e for e in expand if e != 'null'])  # drop null element

# if e != '/n' else '\n'  useless

new_grammar = create_grammar(my_grammar)
print('new', new_grammar)

# print(generate(new_grammar, 'sentence'))
# return list[sentences...]  .named GetSomeRandomSentences has warned
def get_some_random_sentences(grammar, split='=', target='sentence', number=100):
	sentences = []
	for i in range(number):
		sentences.append(generate(create_grammar(grammar, split), target))
	return sentences

print(get_some_random_sentences(my_grammar, '=', 'sentence', 10))

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

# 2-gram
# file_path = '/Users/yaphets/Desktop/movie_comments.csv'

# return list
def token(content):
	return re.findall('\w+', content)

# return list
def file_parse(file_path, coding='utf-8'):
	articles = pd.read_csv(file_path, encoding=coding, low_memory=False)['comment'].tolist()
	content = ''.join(str(articles))
	return token(content)

# from collections import Counter
# with_jieba_cut = Counter(jieba.cut(articles[1000]))
# print(with_jieba_cut.most_common()[:10])

# print(len(file_parse(file_path)))

# return word list, !!! "str" build-in  "string" not built-in
def cut(string): return list(
	jieba.cut(''.join(string[:500000])) if len(string) > 500000 else jieba.cut(''.join(string)))

# words_list = cut(file_parse(file_path))
# return map
def count_words(words_list):
	return Counter(words_list)

# words_count = Counter(words_list)

# return float
def prob_1(word, words_count, words_list):
	return words_count[word] / len(words_list)

# return 2-gram list
def gram2_list(words_list):
	if len(words_list) < 3:
		return []
	return [''.join(words_list[i:i + 2]) for i in range(len(words_list[:-2]))]

# TOKEN_2_GRAM = [''.join(words_list[i:i + 2]) for i in range(len(words_list[:-2]))]

# print(prob_1("鄙视"))

# two words
def prob_2(word1, word2, words_count, words_list):
	length = len(gram2_list(words_list))
	if word1 + word2 in words_count:
		return words_count[word1 + word2] / length
	else:
		return 1 / length

# print(prob_2('热血','澎湃'),prob_2('爱国','人'))
# return float
def get_probablity(sentence, words_count, words_list):
	words = cut(sentence)
	sentence_pro = 1
	for i, word in enumerate(words[:-1]):
		next_ = words[i + 1]
		probablity = prob_2(word, next_, words_count, words_list)
		sentence_pro += probablity
	return sentence_pro

# return map
def sort_sentences_by_probablity(sentences, words_count, words_list):
	sentences_map = {}
	for sen in sentences:
		sentences_map[sen] = get_probablity(sen, words_count, words_list)
	return sentences_map

# return sort list
def generate_best(sentences_map):
	sentences_list = sentences_map.items()
	return sorted(sentences_list, key=lambda x: x[1], reverse=True)

# main
def main():
	file_path = '/Users/yaphets/Desktop/movie_comments.csv'
	words_list = cut(file_parse(file_path))
	words_count = count_words(words_list)
	sentences = get_some_random_sentences(comment_grammar, '=', 'sentence', 10)  # 10
	print(sentences)
	print(generate_best(sort_sentences_by_probablity(sentences, words_count, words_list)))

main()


import pygame
import random
from .Snake import Snake

class Apple:
    def __init__(self):
        x = random.randint(0, 700)
        y = random.randint(0, 500)

        x = 20 * round(x / 20)
        y = 20 * round(y / 20)

        self.snake = Snake()

        self.x = self.original_x = x
        self.y = self.original_y = y

        self.checkPos()

    def checkPos(self):
        checkforpos = True
        while checkforpos:
            for xcoord in self.snake.x:
                while xcoord == self.x:
                    self.x = random.randint(0, 700)
                    self.x = 20 * round(self.x / 20)
                    checkforpos = True
                else:
                    checkforpos = False

            for ycoord in self.snake.x:
                while ycoord == self.y:
                    self.y = random.randint(0, 500)
                    self.y = 20 * round(self.y / 20)
                    checkforpos = True
                else:
                    checkforpos = False

    def draw(self, win):
        pygame.draw.circle(win, (255, 0, 0), (self.x + 5, self.y + 5), 5)

    def reset(self):
        x = random.randint(0, 700)
        y = random.randint(0, 500)

        x = 20 * round(x / 20)
        y = 20 * round(y / 20)

        self.x = self.original_x = x
        self.y = self.original_y = y


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Nov  4 20:20:53 2020

@author: camila
"""

#%% Import
import igraph
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import math
import scipy.sparse.linalg
import random
import threading, queue

import matplotlib.transforms as transform

import spectral_functions as sf

def community_number_error_nbm(file_graph, file_expected, p_eig_array,gamma1=1,gamma2=1,char_split="\t"):
    g = sf.read_construct_g(file_graph)

#%%  teste
    g = sf.read_construct_g(file_graph)
    base_folder="grafos_nao_direcionados/"
    base_expected="grafos_expected"
    file_graph=base_folder+"karate.net"
    file_expected=base_expected+"karate_expected.txt"

#%% Community number error

def community_number_error(file_graph, file_expected, p_eig_array,gamma1=1,gamma2=1,char_split="\t"):
  g = sf.read_construct_g(file_graph)
  mod_mat,_,_ = sf.construct_modularity_generalized(g,gamma1,gamma2)
  mod_mat = mod_mat.transpose()

  p_expected = sf.read_partition_expected(file_expected,char_split)
  k_expected = len(np.unique(p_expected))

  #print(p_expected)

  res_k_est_array = np.zeros(len(p_eig_array))
  res_k_expected_array = np.zeros(len(p_eig_array))

  print(p_eig_array)

  for plarg in p_eig_array:
    #eig_val, eig_vec, eig_pos_ind, eig_neg_ind = sf.calc_eigen(g,mod_mat, plarg)
    eig_val, eig_vec, eig_pos_ind, eig_neg_ind = sf.calc_eigen(g,mod_mat, plarg, which='LM')

    thr = math.sqrt( max(eig_val) )
    k_est = len(eig_val[eig_val > math.sqrt( max(eig_val) )])

    #k_est = len(eig_val[abs(eig_val) > abs( math.sqrt( max(eig_val) ))])

    #print("Largest eigenvalues to calc: "+str(plarg) )
    #print("Largest eigenvalue: " + str(max(eig_val)))
    #print("Lowest eigenvalue: " + str(max(eig_val)))
    #print("Estimation k: " + str(k_est))

    print("plarg="+str(plarg)+": k_expected="+str(k_expected) + ", k_est=" + str(k_est))
    res_k_est_array[math.floor(plarg*len(p_eig_array))-1] = k_est
    res_k_expected_array[math.floor(plarg*len(p_eig_array))-1] = k_expected
  return res_k_est_array, res_k_expected_array

#%% Modularity error

def modularity_error(file_graph, file_expected, p_eig_array,gamma1=1,gamma2=1, char_split="\t"):
  g = sf.read_construct_g(file_graph)
  mod_mat,_,_ = sf.construct_modularity_generalized(g,gamma1,gamma2)
  mod_mat = mod_mat.transpose()

  p_expected = sf.read_partition_expected(file_expected,char_split)
  #print(p_expected)

  comms_est = len(np.unique(p_expected))
  #Calc all - calc estimation
  valQ_exact = sf.calc_Q_partition(g, mod_mat, comms_est, 1, p_expected)

  res_errorQ_perc_array = np.zeros(len(p_eig_array))
  print("p_eig_array")
  print(p_eig_array)

  for p in p_eig_array:
    #valQ_est = sf.calc_Q_partition(g, mod_mat, comms_est, p, p_expected)
    valQ_est = sf.calc_Q_partition(g, mod_mat, comms_est, p, p_expected, which='LM')
    errorQ = valQ_exact - valQ_est
    errorQ_perc = 100*errorQ/valQ_exact
    print("plarg="+str(p)+": valQ_exact="+str(valQ_exact) + ", valQ_est=" + str(valQ_est) + ", error="+str(errorQ) +  ", %=" + str(errorQ_perc))
    #print(math.floor(p*10))
    print(math.floor(p* len(p_eig_array)))
    res_errorQ_perc_array[math.floor(p* len(p_eig_array))-1] = errorQ_perc

  return res_errorQ_perc_array

#%% Plot error

def plot_error(error_array, p_eig_array, n1_array, file_name, ylabel,off=1,start_off=4):

    figure, ax = plt.subplots(figsize=(9, 9))
    #matplotlib.rc('text', usetex = True)

    #fig = plt.figure()
    #ax = plt.axes()

    colors=['blue', 'red', 'green','pink', 'orange','violet','yellow','gray','brown','cyan','black']

    #tr = mtrans.offset_copy(ax.transData, fig=figure, x=0.0, y=-105, units='points')
    tr = transform.Affine2D().translate(0, 0) + ax.transData

    if np.max(error_array) > 100:
        interval_y = 50
        max_y=250
    else:
        interval_y = 10
        max_y=50

    for i, p in enumerate(p_eig_array):
        if i>=start_off:
            if off > 1:
                tr = transform.Affine2D().translate(0, (i-start_off-1)/off) + ax.transData
            else:
                tr = transform.Affine2D().translate(0, off) + ax.transData

            ls=[':','--','-.',':','-.'][i%5]

        curve=math.floor(p*len(p_eig_array))-1
        ax.plot(n1_array,error_array[:,curve], color=colors[curve], transform=tr )#, linestyle=ls, linewidth=lw) #, label="Vertex vectors")       #s=10 ,
        #ax.set_xlabel('x-axis', fontsize = 20)
        print(math.floor(p*len(p_eig_array))-1)
        #for n1 in n1_array:
            #ax.text(n1, errorQ_perc_array_avg[n1-1,math.floor(p*10)-1], n1 ,fontsize=10)

        plt.xticks( n1_array, np.round(n1_array/10,1), fontsize = 24,rotation='horizontal') #
        plt.yticks(fontsize = 24)
        plt.yticks(np.arange(0, max_y+1, interval_y))

    ax.grid()

    #plt.plot(n1_array,errorQ_perc_array_avg[:,0], color='blue') #, label="Vertex vectors")       #s=10 ,
    leg_p = ['$\mathit{p}$=' + str(round(p_eig,1)) + '$\mathit{n}$' for p_eig in p_eig_array]

    ax.set_xlabel("Mixture coefficient ($\mu$)",fontsize = 25)
    ax.set_ylabel(ylabel,fontsize = 25)

    ax.legend(leg_p, prop={'size':18})
    #plt.show()
    plt.savefig(file_name)
     #p_eig_array, labelcolor=colors)
    plt.show()

    #plt.show()

#%% main LFR

def main_teoric_error_lfr(base_folder, base_expected, type_SL='S'):
    results_folder='../results_Tese_2021_3'
    size=1000
    #type_array = ['L']
    #n1_array = np.arange(1,8+1) #1,5+1

    n1_array = np.arange(1,8+1) #1,5+1
    n2_array = np.arange(1,5+1) #1,8+1

    #n1_array = np.arange(1,1+1) #1,5+1
    #n2_array = np.arange(1,1+1) #1,8+1

    p_eig_array = np.linspace(0.1,1,num=10)
    #p_eig_array = np.linspace(0.1,1,num=2)

    errorQ_array = np.zeros( (len(n1_array)*len(n2_array) , len(p_eig_array)) ,dtype=float)
    errorQ_perc_array = np.zeros( (len(n1_array)*len(n2_array), len(p_eig_array)) ,dtype=float)

    k_est_array = np.zeros( (len(n1_array)*len(n2_array), len(p_eig_array)) ,dtype=float)
    k_expected_array = np.zeros( (len(n1_array)*len(n2_array), len(p_eig_array)) ,dtype=float)

    errorQ_array_avg = np.zeros( (len(n1_array) , len(p_eig_array)) ,dtype=float)
    errorQ_perc_array_avg = np.zeros( (len(n1_array), len(p_eig_array)) ,dtype=float)

    k_est_array_avg = np.zeros( (len(n1_array)*len(n2_array), len(p_eig_array)) ,dtype=float)
    k_expected_array_avg = np.zeros( (len(n1_array), len(p_eig_array)) ,dtype=float)

    l=0
    l_avg=0
    for n1 in n1_array:

        #calc average error for n1:
        for n2 in n2_array:
            print("\nGraph: "+str(n1) + "," + str(n2))
            #file_graph=base_folder+"karate.net"
            file_graph=base_folder+"net_Binary_2017_"+type_SL+"1000_"+str(n1)+"_"+str(n2)+".net"
            #file_expected=base_expected+"karate_expected.txt"
            file_expected=base_expected+"com_Binary_2017_"+type_SL+"1000_"+str(n1)+"_"+str(n2)+".dat"

            errorQ_perc_array[l,:] += modularity_error(file_graph, file_expected, p_eig_array)
            errorQ_perc_array_avg[l_avg,:] += abs(errorQ_perc_array[l,:])

            k_est_array[l,:], k_expected_array[l,:] = community_number_error(file_graph, file_expected, p_eig_array,1,1)

            k_expected_array_avg[l_avg,:] += (  k_est_array[l,:] - k_expected_array[l,:] )

            #print(k_est_array)
            l+=1

        l_avg+= 1

    errorQ_perc_array_avg = errorQ_perc_array_avg / n2_array.shape[0]
    k_expected_array_avg = k_expected_array_avg / n2_array.shape[0]

    file_name_errorQ = results_folder+'/exp_mod_error_'+'net_Binary_2017_'+type_SL+'1000'+'.png'
    plot_error(errorQ_perc_array_avg, p_eig_array, n1_array, file_name_errorQ, "Relative error ($\%$)",off=-0.05,start_off=8)

    file_name_k_error = results_folder+'/exp_k_error_'+'net_Binary_2017_'+type_SL+'1000'+'.png'
    plot_error(k_expected_array_avg, p_eig_array, n1_array, file_name_k_error, "Difference on the number of communities",start_off=4)

    #return errorQ_perc_array, k_est_array, k_expected_array

#%% Call - LFR

base_folder="/home/camila/not_sync/Lancichinetti2017/Binary_2017_Lancichinetti2011_S/paj_Binary_2017_S/"
base_expected="/home/camila/not_sync/Lancichinetti2017/Binary_2017_Lancichinetti2011_S/com_Binary_2017_S/"
#errorQ_perc_array, k_est_array, k_expected_array=
main_teoric_error_lfr(base_folder, base_expected, "S")

base_folder="/home/camila/not_sync/Lancichinetti2017/Binary_2017_Lancichinetti2011_L/paj_Binary_2017_L/"
base_expected="/home/camila/not_sync/Lancichinetti2017/Binary_2017_Lancichinetti2011_L/com_Binary_2017_L/"
#errorQ_perc_array, k_est_array, k_expected_array=
main_teoric_error_lfr(base_folder, base_expected, "L")

#[print("plarg=",round(0.1+(p/10)),":",np.max(errorQ_perc_array[:,p])) for p in np.arange(0,10)]
#[print("plarg=",round(0.1+(p/10)),":",np.max(errorQ_perc_array[:,p])) for p in np.arange(0,10)]

#%% main_example
def main_teoric_error_example(base_folder, base_expected,char_split="\t"):
    n1_array = np.arange(1,2) #1,5+1
    n2_array = np.arange(1,2) #1,8+1

    p_eig_array = np.linspace(0.1,1,num=10)

    errorQ_array = np.zeros( (len(n1_array)*len(n2_array) , len(p_eig_array)) ,dtype=float)
    errorQ_perc_array = np.zeros( (len(n1_array)*len(n2_array), len(p_eig_array)) ,dtype=float)

    k_est_array = np.zeros( (len(n1_array)*len(n2_array), len(p_eig_array)) ,dtype=float)
    k_expected_array = np.zeros( (len(n1_array)*len(n2_array), len(p_eig_array)) ,dtype=float)

    l=0

    name='dolphins'
    file_graph=base_folder+name+".paj"
    file_expected=base_expected+name+"_expected.txt"

    errorQ_perc_array[l,:] = modularity_error(file_graph, file_expected, p_eig_array,char_split=char_split)
    k_est_array[l,:], k_expected_array[l,:] = community_number_error(file_graph, file_expected, p_eig_array,1,1,char_split)
    print(k_est_array)

    return errorQ_perc_array, k_est_array, k_expected_array

errorQ_perc_array, k_est_array, k_expected_array=main_teoric_error_example("grafos_nao_direcionados/", "grafos_expected/",char_split=' ')

#%% Teoric analysis

#%%% Teoric example: plot

## Eigenvalue distribution

def teoric_eigenvalues(g, mod_mat, plarg):
  zero_thr = 1e-15

  eig_val, eig_vec, eig_pos_ind, eig_neg_ind = sf.calc_eigen(g, mod_mat, plarg)

  thr = math.sqrt( max(eig_val) )
  k_est = len(eig_val[eig_val > math.sqrt( max(eig_val) )])
  print("Largest eigenvalues to calc: "+str(plarg) )
  print("Largest eigenvalue: " + str(max(eig_val)))
  print("Lowest eigenvalue: " + str(max(eig_val)))
  print("Estimation k: " + str(k_est))

  #TODO: Estimation k vs real communities

  #xx = np.linspace(0,100,101)   # consider x values 0, 1, .., 100
  #eigenvalues = np.array([np.sort(np.linalg.eigvals([[40,0,4],[0,0,4],[4,4,x]])) for x in xx])
  y=np.empty(len(eig_val))
  y.fill(0)
  print(y)

  print("eigenvalues'")
  print(sorted(eig_val, reverse=True))
  #print(eig_val)
  #print(eig_val == eig_val.real)

  print("* Zero eigenvalue exists?")
  print(eig_val[(eig_val<= zero_thr) & (eig_val >= -zero_thr)])
  print("...")
  #print ( ((eig_val <= zero_thr) & (eig_val >= -zero_thr)).any() )
  print(np.logical_and( eig_val <= zero_thr , eig_val >= -zero_thr).any())
  eig_zero = np.logical_and( eig_val <= zero_thr , eig_val >= -zero_thr)
  print(eig_zero)
  eig_zero_ind = np.where(eig_zero== True)
  print(eig_zero_ind[0])

  print("* 1 is an eigenvector associated with 0 eigenvalue?")
  #associated eigenvectors
  for c in eig_zero_ind[0]:
    print("ind:"+str(c))
    print(eig_vec[:,c])

#1 nao e um autovetor!

  return eig_val, thr

#teoric_eigenvalues(g, mod_mat, plarg)

#%%% Plot

def plot_eigvalues(eig_val, thr):
  #Plot
  #cont teoric_eigenvalues(g, mod_mat, plarg):

  figure, ax = plt.subplots()
  #draw_circle = plt.Circle((0, 0), thr)
  ax.set_xlim((min(eig_val)-1, max(eig_val)+1))
  ax.set_ylim((-thr-1, thr+1))
  draw_circle = plt.Circle((0, 0), thr, fill=False)

  ax.scatter(eig_val, y=np.zeros(len(eig_val)), label="Eigenvalues")
  ax.scatter([-thr,thr], [0,0], label="Threshold", color="red", marker="s")

  ax.set_aspect(1)
  ax.add_artist(draw_circle)
  plt.title('Circle')
  plt.legend()
  plt.show()

#%%% Teoric example -

def main_teoric(file_graph,file_expected,plarg,gamma1=1,gamma2=1,char_split="\t"):

    g = sf.read_construct_g(file_graph)
    mod_mat, _,_ = sf.construct_modularity_generalized(g,gamma1,gamma2)
    mod_mat = mod_mat.transpose() #por que?

    eig_val, thr = teoric_eigenvalues(g, mod_mat, plarg)
    plot_eigvalues(eig_val, thr)

    p_expected = sf.read_partition_expected(file_expected,char_split)
    #print(p_expected)

    p_eig_array = np.linspace(0.1,1,num=10)
    #p_eig_array = np.linspace(0.1,1,num=2)
    modularity_error(file_graph, file_expected, p_eig_array)

#%% Teoric: Call main

def call_main_teoric_example():
    base_folder="/home/camila/not_sync/Lancichinetti2017/Binary_2017_Lancichinetti2011_S/paj_Binary_2017_S/"
    base_expected="/home/camila/not_sync/Lancichinetti2017/Binary_2017_Lancichinetti2011_S/com_Binary_2017_S/"
    n1=6
    n2=1
    #file_graph=base_folder+"karate.net"
    #file_expected=base_expected+"karate_expected.txt"

    file_graph=base_folder+"net_Binary_2017_S1000_"+str(n1)+"_"+str(n2)+".net"
    file_expected=base_expected+"com_Binary_2017_S1000_"+str(n1)+"_"+str(n2)+".dat"

    main_teoric(file_graph, file_expected,plarg=0.1,gamma1=1,gamma2=1)

#call_main_teoric_example()


from django.http import JsonResponse
from django.shortcuts import render
from main.models import *
from .serializers import UserSerializer
from rest_framework.decorators import api_view
import requests
from random import randint
from django.db.models import Q

from main.models import *

@api_view(['POST'])
def add_user(request):
    data = request.data
    room_code = data['room_code']
    game = Game_tic.objects.get(name=room_code)
    try:
        player1 = Player_tic.objects.filter(player__name=game.name).get(choice='X')
        player2 = Player_tic.objects.filter(player__name=game.name).get(choice='O')
        return JsonResponse({'player_1': player1.image, 'player_2': player2.image})
    except:
        player1 = Player_tic.objects.get(player__name=game.name)
        return JsonResponse({'player_1': player1.image})

@api_view(['POST'])
def add_rating(request):
    data = request.data
    username = data['username']
    user = User.objects.get(username=username)
    user.rating += randint(5,20)
    user.save()

    if user.rating >=30:
        user.rank = Rank.objects.get(title='Bronze')
    if user.rating >=70:
        user.rank = Rank.objects.get(title='Silver')
    if user.rating >=150:
        user.rank = Rank.objects.get(title='Gold')

    user.save()
    return JsonResponse({'message': f'added 20 points to {user.username}'})

@api_view(['POST'])
def delete_user(request):
    data = request.data
    nickname = data.get('nickname')
    player = Player_tic.objects.get(nickname=nickname)
    game = Game_tic.objects.get(player__nickname=player.nickname)
    player.delete()
    print('deleted:', nickname, 'game:', game.name)
    if game.player.count() == 0:
        game.delete()
        print(game.name, ' - deleted')

    response = JsonResponse({'Action': 'User deleted'})
    response.delete_cookie('char_choice')
    response.delete_cookie('nickname')
    response.delete_cookie('image')

    return response


from django.http.response import Http404
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated

from bvs.abstract.viewsets import AbstractViewSet
from bvs.physiotherapy.models import Physiotherapy
from bvs.physiotherapy.serializers import PhysiotherapySerializer

class PhysiotherapyViewSet(AbstractViewSet):
    http_method_names = ("post", "get", "put", "delete")
    permission_classes = (IsAuthenticated,)
    serializer_class = PhysiotherapySerializer

    def get_queryset(self):
        patient_pk = self.kwargs["patient_pk"]
        if patient_pk is None:
            return Http404
        queryset = Physiotherapy.objects.filter(patient__public_id=patient_pk)

        return queryset

    def get_object(self):
        obj = Physiotherapy.objects.get_object_by_public_id(self.kwargs["pk"])

        self.check_object_permissions(self.request, obj)

        return obj

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    @action(detail=False)
    def physiotherapy_count(self, request):
        physiotherapy_count = Physiotherapy.objects.count()
        return Response({'physiotherapy_count': physiotherapy_count})


#!/usr/bin/env python3
"""Graph from OSM network data.
Note:
    - Majority of code is from `osmnx` package.
    - Author only made minor modification to integrate `osmnx` features into `Graph` class.
        - We do not use `geopandas` module.
        - Some options that are not in use of our purpose are ignored.
        - Type added.
"""
import itertools
import warnings
from collections import Counter
from collections.abc import Generator
from dataclasses import dataclass
from datetime import date
from functools import cached_property

import networkx
import numpy as np
from networkx import MultiDiGraph
from numpy.typing import NDArray
from shapely.geometry import box
from shapely.geometry import LineString
from shapely.geometry import MultiPolygon
from shapely.geometry import Point
from shapely.ops import split
from shapely.strtree import STRtree

from pesgen import __version__
from pesgen.geometry import Polygon

TODAY = (date.today()).strftime("%d/%m/%Y")
TAG_NODES = ["ref", "highway"]
TAG_PATHS = [
    "bridge",
    "tunnel",
    "oneway",
    "lanes",
    "ref",
    "name",
    "highway",
    "maxspeed",
    "service",
    "access",
    "area",
    "landuse",
    "width",
    "est_width",
    "junction",
]

METADATA: dict[str, str] = {
    "created_date": TODAY,
    "created_with": f"pesgen {__version__}",
    "crs": "EPSG:4326",
}
EARTH_RADIUS_M: float = 6_371_009

LL_TYPE = NDArray[np.float64]

QUADRAT_WIDTH: float = 0.05
MIN_NUM: int = 3

@dataclass
class Graph:

    osm_network: dict
    nx_graph: MultiDiGraph = MultiDiGraph(**METADATA)

    def __post_init__(self):

        assert "elements" in self.osm_network, "Graph: empty network data!"

        nodes, paths = self.parse_node_path()

        node_test = np.asarray(
            [[nodes[d]["x"], nodes[d]["y"]] for d in nodes], dtype=np.float64
        )

        # add each osm node to the graph
        for node, data in nodes.items():
            self.nx.add_node(node, **data)

        # add each osm way (ie, a path of edges) to the graph
        self.add_paths(list(paths.values()))

        # retain only the largest connected component if retain_all is False
        self.get_largest_component()

        # add length (great-circle distance between nodes) attribute to each edge
        if len(self.nx.edges) > 0:
            self.add_edge_lengths()

    @cached_property
    def coord(self) -> NDArray[np.float64]:
        """Return coordinates of nodes."""
        return np.asarray(
            [[n[1]["x"], n[1]["y"]] for n in self.nx.nodes(data=True)],  # type: ignore
            dtype=np.float64,
        )

    def add_paths(self, paths: list) -> None:
        """
        Add a list of paths to the graph as edges.
        Parameters

        Args:
            G (MultiDiGraph): graph to add paths to
            paths (list): list of paths' tag:value attribute data dicts
        """
        # the values OSM uses in its 'oneway' tag to denote True, and to denote
        # travel can only occur in the opposite direction of the node order. see:
        # https://wiki.openstreetmap.org/wiki/Key:oneway
        # https://www.geofabrik.de/de/data/geofabrik-osm-gis-standard-0.7.pdf
        oneway_values = {"yes", "true", "1", "-1", "reverse", "T", "F"}
        reversed_values = {"-1", "reverse", "T"}

        for path in paths:

            # extract/remove the ordered list of nodes from this path element so
            # we don't add it as a superfluous attribute to the edge later
            nodes = path.pop("nodes")

            # reverse the order of nodes in the path if this path is both one-way
            # and only allows travel in the opposite direction of nodes' order
            is_one_way = _is_path_one_way(path, oneway_values)
            if is_one_way and _is_path_reversed(path, reversed_values):
                nodes.reverse()

            path["oneway"] = is_one_way

            # zip path nodes to get (u, v) tuples like [(0,1), (1,2), (2,3)].
            edges = list(zip(nodes[:-1], nodes[1:]))

            # add all the edge tuples and give them the path's tag:value attrs
            path["reversed"] = False
            self.nx.add_edges_from(edges, **path)

            # if the path is NOT one-way, reverse direction of each edge and add
            # this path going the opposite direction too
            if not is_one_way:
                path["reversed"] = True
                self.nx.add_edges_from([(v, u) for u, v in edges], **path)

    def simplify_graph(self):
        """
        Simplify a graph's topology by removing interstitial nodes.
        Simplifies graph topology by removing all nodes that are not intersections
        or dead-ends. Create an edge directly between the end points that
        encapsulate them, but retain the geometry of the original edges, saved as
        a new `geometry` attribute on the new edge. Note that only simplified
        edges receive a `geometry` attribute. Some of the resulting consolidated
        edges may comprise multiple OSM ways, and if so, their multiple attribute
        values are stored as a list.
        Parameters

        Note:
            - Always in strict mode.
        """
        if "simplified" in self.nx.graph and self.nx.graph["simplified"]:
            raise RuntimeError(
                "Graph: This graph has already been simplified, cannot simplify it again."
            )

        # define edge segment attributes to sum upon edge simplification
        attrs_to_sum = {"length", "travel_time"}

        # make a copy to not mutate original graph object caller passed in
        G: MultiDiGraph = self.nx.copy()
        all_nodes_to_remove = []
        all_edges_to_add = []

        # generate each path that needs to be simplified
        for path in _get_paths_to_simplify(G):

            # add the interstitial edges we're removing to a list so we can retain
            # their spatial geometry
            path_attributes = dict()
            for u, v in zip(path[:-1], path[1:]):

                # there should rarely be multiple edges between interstitial nodes
                # usually happens if OSM has duplicate ways digitized for just one
                # street... we will keep only one of the edges (see below)
                edge_count = G.number_of_edges(u, v)
                if edge_count != 1:
                    warnings.warn(
                        f"Graph: Found {edge_count} edges between {u} and {v} when simplifying"
                    )

                # get edge between these nodes: if multiple edges exist between
                # them (see above), we retain only one in the simplified graph
                edge_data = G.edges[u, v, 0]
                for attr in edge_data:
                    if attr in path_attributes:
                        # if this key already exists in the dict, append it to the
                        # value list
                        path_attributes[attr].append(edge_data[attr])
                    else:
                        # if this key doesn't already exist, set the value to a list
                        # containing the one value
                        path_attributes[attr] = [edge_data[attr]]

            # consolidate the path's edge segments' attribute values
            for attr in path_attributes:
                if attr in attrs_to_sum:
                    # if this attribute must be summed, sum it now
                    path_attributes[attr] = sum(path_attributes[attr])
                elif len(set(path_attributes[attr])) == 1:
                    # if there's only 1 unique value in this attribute list,
                    # consolidate it to the single value (the zero-th):
                    path_attributes[attr] = path_attributes[attr][0]
                else:
                    # otherwise, if there are multiple values, keep one of each
                    path_attributes[attr] = list(set(path_attributes[attr]))

            # construct the new consolidated edge's geometry for this path
            path_attributes["geometry"] = LineString(
                [
                    Point((G.nodes[node]["x"], G.nodes[node]["y"]))
                    for node in path
                ]
            )

            # add the nodes and edge to their lists for processing at the end
            all_nodes_to_remove.extend(path[1:-1])
            all_edges_to_add.append(
                {
                    "origin": path[0],
                    "destination": path[-1],
                    "attr_dict": path_attributes,
                }
            )

        # for each edge to add in the list we assembled, create a new edge between
        # the origin and destination
        for edge in all_edges_to_add:
            G.add_edge(
                edge["origin"], edge["destination"], **edge["attr_dict"]
            )

        # finally remove all the interstitial nodes between the new edges
        G.remove_nodes_from(set(all_nodes_to_remove))

        # remove any connected components that form a self-contained ring
        # without any endpoints
        wccs = networkx.weakly_connected_components(G)
        nodes_in_rings = set()
        for wcc in wccs:
            if not any(_is_endpoint(G, n) for n in wcc):
                nodes_in_rings.update(wcc)
        G.remove_nodes_from(nodes_in_rings)

        # mark graph as having been simplified
        G.graph["simplified"] = True
        self.nx_graph = G

    def count_streets_per_node(self) -> None:
        """
        Count how many physical street segments connect to each node in a graph.
        This function uses an undirected representation of the graph and special
        handling of self-loops to accurately count physical streets rather than
        directed edges. Note: this function is automatically run by all the
        `graph.graph_from_x` functions prior to truncating the graph to the
        requested boundaries, to add accurate `street_count` attributes to each
        node even if some of its neighbors are outside the requested graph
        boundaries.
        """
        nodes = self.nx.nodes

        # get one copy of each self-loop edge, because bi-directional self-loops
        # appear twice in the undirected graph (u,v,0 and u,v,1 where u=v), but
        # one-way self-loops will appear only once
        Gu = self.nx.to_undirected(reciprocal=False, as_view=True)
        self_loop_edges = set(networkx.selfloop_edges(Gu))

        # get all non-self-loop undirected edges, including parallel edges
        non_self_loop_edges = [
            e for e in Gu.edges(keys=False) if e not in self_loop_edges
        ]

        # make list of all unique edges including each parallel edge unless the
        # parallel edge is a self-loop, in which case we don't double-count it
        all_unique_edges = non_self_loop_edges + list(self_loop_edges)

        # flatten list of (u, v) edge tuples to count how often each node appears
        edges_flat = itertools.chain.from_iterable(all_unique_edges)
        counts = Counter(edges_flat)
        spn = {node: counts[node] for node in nodes}
        networkx.set_node_attributes(self.nx, values=spn, name="street_count")

    def truncate(self, polygon: Polygon) -> None:
        """
        Remove every node in graph that falls outside a Polygon.
        Parameters

        Args:
            polygon (Polygon): pesgen.geometry.Polygon
            only retain nodes in graph that lie within this geometry
        """

        # first identify all nodes whose point geometries lie within the polygon
        osm_id, gs_nodes = _graph_to_gdf_nodes(self.nx)
        # Find all points inside the polygon
        to_keep = _intersect_index_quadrats(gs_nodes, osm_id, polygon)

        if to_keep.shape[0] == 0:
            # no graph nodes within the polygon: can't create a graph from that
            raise ValueError(
                "Graph: Found no graph nodes within the requested polygon"
            )

        # Now identify all nodes whose point geometries lie outside the polygon
        nodes_outside = np.setdiff1d(osm_id, to_keep)

        # Remove from the graph all those nodes that lie outside the polygon
        # make a copy to not mutate original graph object caller passed in
        self.nx_graph = self.nx.copy()
        self.nx_graph.remove_nodes_from(nodes_outside)

    def add_edge_lengths(self):
        """
        Add `length` attribute (in meters) to each edge.
        """
        uvk = tuple(self.nx.edges)

        # extract edge IDs and corresponding coordinates from their nodes
        x = self.nx.nodes(data="x")  # type: ignore
        y = self.nx.nodes(data="y")  # type: ignore

        try:
            # two-dimensional array of coordinates: y0, x0, y1, x1
            c = np.asarray([(y[u], x[u], y[v], x[v]) for u, v, _ in uvk])
        except KeyError:  # pragma: no cover
            raise KeyError(
                "Graph: some edges missing nodes, possibly due to input data clipping issue"
            )

        # calculate great circle distances, round, and fill nulls with zeros
        dists = _great_circle_vec(c[:, 0], c[:, 1], c[:, 2], c[:, 3]).round(3)
        dists[np.isnan(dists)] = 0
        networkx.set_edge_attributes(
            self.nx, values=dict(zip(uvk, dists)), name="length"
        )

    def get_largest_component(self) -> None:
        """
        Return the largest connected component of the graph.
        """
        is_connected = networkx.is_weakly_connected
        connected_components = networkx.weakly_connected_components

        if not is_connected(self.nx):
            # get all the connected components in graph then identify the largest
            largest_cc = max(connected_components(self.nx), key=len)

            # induce (frozen) subgraph then unfreeze it by making new MultiDiGraph
            self.nx_graph = MultiDiGraph(self.nx.subgraph(largest_cc))

    def parse_node_path(self) -> tuple[dict, dict]:
        """
        Construct dicts of nodes and paths from an Overpass response.
        Parameters

        Note: Copied and modified from `osmnx` package.
        """
        nodes = dict()
        paths = dict()
        for element in self.osm_network["elements"]:
            if element["type"] == "node":
                nodes[element["id"]] = _convert_node(element)
            elif element["type"] == "way":
                paths[element["id"]] = _convert_path(element)

        return nodes, paths

    @property
    def nx(self) -> MultiDiGraph:
        """Return `networkx` Graph object."""
        return self.nx_graph

def _get_paths_to_simplify(G: MultiDiGraph) -> Generator:
    """
    Generate all the paths to be simplified between endpoint nodes.
    The path is ordered from the first endpoint, through the interstitial nodes,
    to the second endpoint.
    Parameters

    Args:
        MultiDiGraph: input graph
    """
    # first identify all the nodes that are endpoints
    endpoints = {n for n in G.nodes if _is_endpoint(G, n)}

    # for each endpoint node, look at each of its successor nodes
    for endpoint in endpoints:
        for successor in G.successors(endpoint):
            if successor not in endpoints:
                # if endpoint node's successor is not an endpoint, build path
                # from the endpoint node, through the successor, and on to the
                # next endpoint node
                yield _build_path(G, endpoint, successor, endpoints)

def _build_path(
    G: MultiDiGraph, endpoint: int, endpoint_successor: int, endpoints: set
) -> list[int]:
    """
    Build a path of nodes from one endpoint node to next endpoint node.
    Parameters

    Args:
        G (MultiDiGraph): input graph
        endpoint (int): the endpoint node from which to start the path
        endpoint_successor (int): the successor of endpoint through which the
        endpoints (set): the set of all nodes in the graph that are endpoints

    Returns:
        list: the first and last items in the resulting path list are endpoint nodes, and all other items are interstitial nodes that can be removed subsequently
    """
    # start building path from endpoint node through its successor
    path = [endpoint, endpoint_successor]

    # for each successor of the endpoint's successor
    for successor in G.successors(endpoint_successor):
        if successor not in path:
            # if this successor is already in the path, ignore it, otherwise add
            # it to the path
            path.append(successor)
            while successor not in endpoints:
                # find successors (of current successor) not in path
                successors = [
                    n for n in G.successors(successor) if n not in path
                ]

                # 99%+ of the time there will be only 1 successor: add to path
                if len(successors) == 1:
                    successor = successors[0]
                    path.append(successor)

                # handle relatively rare cases or OSM digitization quirks
                elif len(successors) == 0:
                    if endpoint in G.successors(successor):
                        # we have come to the end of a self-looping edge, so
                        # add first node to end of path to close it and return
                        return path + [endpoint]
                    else:
                        # this can happen due to OSM digitization error where
                        # a one-way street turns into a two-way here, but
                        # duplicate incoming one-way edges are present
                        warnings.warn(
                            f"Graph: Unexpected simplify pattern handled near {successor}"
                        )
                        return path
                else:
                    # if successor has >1 successors, then successor must have
                    # been an endpoint because you can go in 2 new directions.
                    # this should never occur in practice
                    raise Exception(
                        f"Unexpected simplify pattern failed near {successor}"
                    )

            # if this successor is an endpoint, we've completed the path
            return path

    # if endpoint_successor has no successors not already in the path, return
    # the current path: this is usually due to a digitization quirk on OSM
    return path

def _is_endpoint(G: MultiDiGraph, node: int) -> bool:
    """
    Is node a true endpoint of an edge.
    Return True if the node is a "real" endpoint of an edge in the network,
    otherwise False. OSM data includes lots of nodes that exist only as points
    to help streets bend around curves. An end point is a node that either:
    1) is its own neighbor, ie, it self-loops.
    2) or, has no incoming edges or no outgoing edges, ie, all its incident
    edges point inward or all its incident edges point outward.
    3) or, it does not have exactly two neighbors and degree of 2 or 4.
    Parameters

    Args:
        G (MultiDiGraph): input graph
        node (int): the node to examine
    """
    neighbors = set(list(G.predecessors(node)) + list(G.successors(node)))
    n = len(neighbors)
    d = G.degree(node)

    # rule 1
    if node in neighbors:
        # if the node appears in its list of neighbors, it self-loops
        # this is always an endpoint.
        return True

    # rule 2
    elif G.out_degree(node) == 0 or G.in_degree(node) == 0:
        # if node has no incoming edges or no outgoing edges, it is an endpoint
        return True

    # rule 3
    elif not (n == 2 and (d == 2 or d == 4)):
        # else, if it does NOT have 2 neighbors AND either 2 or 4 directed
        # edges, it is an endpoint. either it has 1 or 3+ neighbors, in which
        # case it is a dead-end or an intersection of multiple streets or it has
        # 2 neighbors but 3 degree (indicating a change from oneway to twoway)
        # or more than 4 degree (indicating a parallel edge) and thus is an
        # endpoint
        return True

    # rule 4
    # if none of the preceding rules returned true, then it is not an endpoint
    else:
        return False

def _intersect_index_quadrats(
    geometries: list[Point], osm_id: NDArray[np.int64], polygon: Polygon
) -> NDArray[np.int64]:
    """
    Identify geometries that intersect a (multi)polygon.
    Uses an r-tree spatial index and cuts polygon up into smaller sub-polygons
    for r-tree acceleration. Ensure that geometries and polygon are in the
    same coordinate reference system.
    Parameters

    Note:
        - Unlike `osmnx` package, we directly use `shapely.strtree.STRtree` directly.

    Args:
        geometries (geopandas.GeoSeries): the geometries (Points) to intersect with the polygon
        osm_id (NDArray[np.int64]): the index of the graph nodes
        polygon (Polygon): the polygon to intersect with the geometries

    Returns
        set: index labels of geometries that intersected polygon
    """
    # create an r-tree spatial index for the geometries
    s_index = STRtree(geometries)
    # Shapely geometries are not hashable.
    index_by_id = {id(pt): i for i, pt in enumerate(geometries)}

    # cut the polygon into chunks for spatial index intersecting
    multipoly = _quadrat_cut_geometry(polygon)
    geoms_in_poly: set = set()

    # loop through each chunk of the polygon to find intersecting geometries
    for poly in multipoly.geoms:

        poly = poly.buffer(0.0)
        if poly.is_valid and poly.area > 0:

            # Approximated matches
            b_box = box(*poly.bounds)
            pts_in_box = s_index.query(b_box)
            osm_id_in_box = osm_id[pts_in_box]
            # Update tree with approximated match
            s_index_appx = STRtree(
                s_index.geometries.take(pts_in_box).tolist()
            )

            # Precise query
            geoms_in_poly.update(
                osm_id_in_box[s_index_appx.query(poly, predicate="intersects")]
            )

    return np.asarray(list(geoms_in_poly), dtype=np.int64)

def _quadrat_cut_geometry(polygon: Polygon) -> MultiPolygon:
    """
    Split a Polygon or MultiPolygon up into sub-polygons of a specified size.
    Parameters

    Args:
        polygon (Polygon): the geometry to split up into smaller sub-polygons

    Returns
        MultiPolygon
    """
    # create n evenly spaced points between the min and max x and y bounds
    west, south, east, north = polygon.geometry.bounds  # type: ignore
    x_num = int(np.ceil((east - west) / QUADRAT_WIDTH) + 1)
    y_num = int(np.ceil((north - south) / QUADRAT_WIDTH) + 1)
    x_points = np.linspace(west, east, num=max(x_num, MIN_NUM))
    y_points = np.linspace(south, north, num=max(y_num, MIN_NUM))

    # create a quadrat grid of lines at each of the evenly spaced points
    vertical_lines = [
        LineString([(x, y_points[0]), (x, y_points[-1])]) for x in x_points
    ]
    horizontal_lines = [
        LineString([(x_points[0], y), (x_points[-1], y)]) for y in y_points
    ]
    lines = vertical_lines + horizontal_lines

    # recursively split the geometry by each quadrat line
    polys = [polygon.geometry]

    for line in lines:
        # split polygon by line if they intersect, otherwise just keep it
        split_geoms = [
            split(p, line).geoms if p.intersects(line) else [p] for p in polys
        ]
        # now flatten the list and process these split geoms on the next line in the list of lines
        polys = [g for g_list in split_geoms for g in g_list]

    return MultiPolygon(polys)

def _graph_to_gdf_nodes(
    G: MultiDiGraph,
) -> tuple[NDArray[np.int64], list[Point]]:
    """
    Convert a MultiDiGraph to node and/or edge GeoDataFrames.
    This function is the inverse of `graph_from_gdfs`.
    Parameters

    Args:
        G: networkx.MultiDiGraph
    """
    if not G.nodes:  # pragma: no cover
        raise ValueError("graph contains no nodes")

    osm_id, data_xy = zip(*G.nodes(data=True))

    nodes: list[Point] = [Point(d["x"], d["y"]) for d in data_xy]  # type: ignore

    return np.asarray(osm_id, dtype=np.int64), nodes

def _great_circle_vec(
    lat1: LL_TYPE, lng1: LL_TYPE, lat2: LL_TYPE, lng2: LL_TYPE
) -> NDArray[np.float64]:
    """
    Calculate great-circle distances between pairs of points.
    Vectorized function to calculate the great-circle distance between two
    points' coordinates or between arrays of points' coordinates using the
    haversine formula. Expects coordinates in decimal degrees.
    Parameters

    Args:
        lat1 (NDArray[np.float64]): first point's latitude coordinate
        lng1 (NDArray[np.float64]): first point's longitude coordinate
        lat2 (NDArray[np.float64]): second point's latitude coordinate
        lng2 (NDArray[np.float64]): second point's longitude coordinate

    Returns:
        NDArray[np.float64]: distance from each (lat1, lng1) to each (lat2, lng2) in units of earth_radius
    """
    y1 = np.deg2rad(lat1)
    y2 = np.deg2rad(lat2)
    dy = y2 - y1

    x1 = np.deg2rad(lng1)
    x2 = np.deg2rad(lng2)
    dx = x2 - x1

    h = np.sin(dy / 2) ** 2 + np.cos(y1) * np.cos(y2) * np.sin(dx / 2) ** 2
    h = np.minimum(1, h)  # protect against floating point errors
    arc = 2.0 * np.arcsin(np.sqrt(h))

    # return distance in units of earth_radius
    return arc * EARTH_RADIUS_M

def _convert_node(element: dict) -> dict:
    """
    Convert an OSM node element into the format for a networkx node.
    Parameters

    Note: Copied from `osmnx` package.
    """
    node = {"y": element["lat"], "x": element["lon"]}
    if "tags" in element:
        for useful_tag in TAG_NODES:
            if useful_tag in element["tags"]:
                node[useful_tag] = element["tags"][useful_tag]
    return node

def _convert_path(element: dict) -> dict:
    """
    Convert an OSM way element into the format for a networkx path.
    Parameters

    Note: Copied from `osmnx` package.
    """
    path = {"osmid": element["id"]}

    # remove any consecutive duplicate elements in the list of nodes
    path["nodes"] = [group[0] for group in itertools.groupby(element["nodes"])]

    if "tags" in element:
        for useful_tag in TAG_PATHS:
            if useful_tag in element["tags"]:
                path[useful_tag] = element["tags"][useful_tag]
    return path

def _is_path_one_way(path: dict, oneway_values: set) -> bool:
    """
    Determine if a path of nodes allows travel in only one direction.
    Parameters

    Args:
        path (dict): a path's tag:value attribute data
        oneway_values (set): the values OSM uses in its 'oneway' tag to denote True

    Returns:
        bool
    """

    return (
        True
        if ("oneway" in path and path["oneway"] in oneway_values)
        or ("junction" in path and path["junction"] == "roundabout")
        else False
    )

def _is_path_reversed(path: dict, reversed_values: set) -> bool:
    """
    Determine if the order of nodes in a path should be reversed.
    Parameters

    Args:
        path (dict): a path's tag:value attribute data
        reversed_values (set): the values OSM uses in its 'oneway' tag to denote travel can only

    Returns:
        bool
    """

    return (
        True
        if "oneway" in path and path["oneway"] in reversed_values
        else False
    )

def graph_from_place(query: str):
    pass


from cc10.Queue import Queue

class AnimalShelter:

    """
    creates empty queues one for cats and one for dogs
    """
    def __init__(self):
        self.queue_cats =Queue()
        self.queue_dogs =Queue()
    """
    prints string that represents the queue
    """
    def str(self):
        if self.queue_cats.front is not None and self.queue_dogs.front is None:
            return self.queue_cats.__str__()
        elif self.queue_cats.front is None and self.queue_dogs.front is not None:
            return self.queue_dogs.__str__()
        elif self.queue_cats.front is None and self.queue_dogs.front is None:
            return "empty queue"
        else :
            return (self.queue_dogs.__str__()   , self.queue_cats.__str__()  )

    """
    adds a new value to the back of the queue with an O(1) Time performance.
    Arguments: animal
    Returns : nothing
    """
    def enqueue(self,animal):

        if animal["species"]=="cat":
            self.queue_cats.enqueue_queue(animal)
        if animal["species"] == "dog":
            self.queue_dogs.enqueue_queue(animal)

    """
    Removes a value based on the given pref from the front of the queue with an O(1) Time performance
    Arguments: pref
    Returns: the removed value from the front of the queue
    """
    def dequeue(self,pref):

        if self.queue_cats.front==None and self.queue_dogs.front==None :
            return "you can't dequeue from empty queue"
        if pref=="cat" and self.queue_cats.front is not None:
            return self.queue_cats.dequeue_queue()
        elif pref=="cat" and self.queue_cats.front is None:
            return "you can't dequeue from empty queue"
        elif pref=="dog"and self.queue_dogs.front is not None:
            return self.queue_dogs.dequeue_queue()
        elif pref=="dog"and self.queue_dogs.front is None:
            return "you can't dequeue from empty queue"
        else:
            return "null"

queue = AnimalShelter()
animal0 = {
    "species" : "cat",
    "name" : "yummi"
}

animal1 = {
    "species" : "cat",
    "name" : "rengar"
}

animal2 = {
    "species" : "dog",
    "name" : "nasus"
}

animal3 = {
    "species" : "dog",
    "name" : "warwick"
}

queue.enqueue(animal0)
queue.enqueue(animal1)
queue.enqueue(animal2)
queue.enqueue(animal3)

print(queue.dequeue("cat"))
print(queue.dequeue("dog"))
print(queue.dequeue("cat"))
print(queue.dequeue("dog"))
print(queue.dequeue("abcd"))
print(queue.dequeue("dog"))
print(queue.dequeue("cat"))


import os
import re
import ast
import errno
import shutil

import cv2
import numpy

from robot.api import logger
from robot.utils import get_link_path
from robot.libraries.BuiltIn import BuiltIn
from robot.libraries.BuiltIn import RobotNotRunningError

from PolarisLibrary.base import keyword
from PolarisLibrary.utils.types import is_falsy
from PolarisLibrary.base import PolarisInterface

class ScreenshotKeywords(PolarisInterface):

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

        self._screenshot_index = {}
        self._screenshot_path_stack = []
        self.screenshot_root_directory = None
        self.max_resolution = (5000, 5000)

        PolarisInterface.screenshot = self

    @keyword
    def set_screenshot_directory(self, path, persist=False):
        """ Sets default screenshot directory
        """
        path = os.path.abspath(path)

        try:
            shutil.rmtree(path)
        except WindowsError:
            pass

        self._create_directory(path)

        if is_falsy(persist):
            self._screenshot_path_stack.append(self.screenshot_root_directory)

        self.screenshot_root_directory = path

    @keyword
    def capture_screenshot(self, filename='screenshot-{index}.png', crop=True, coord=[], publish=True):
        """ Captures a screenshot
        """
        path, link = self._get_screenshot_paths(filename)
        self._create_directory(path)

        PolarisInterface.webdriver.save_screenshot(path)

        # This is a fix to compensate Winium inability to take a isolated screenshot of the application.
        # By default, it Winium takes a screenshot of the desktop.
        if crop:
            _bounding_box = PolarisInterface.webdriver.get_boundingrect(PolarisInterface.window_ui)
            if _bounding_box != PolarisInterface.boundingbox:
                PolarisInterface.boundingbox = _bounding_box

            _bounding_box = map(int, _bounding_box)
            _bounding_box = numpy.array(_bounding_box)
            _bounding_box[_bounding_box < 0] = 0
            _bounding_box = _bounding_box.tolist()

            img = cv2.imread(path)
            crop_img = img[_bounding_box[1]:(_bounding_box[1] + _bounding_box[3]),
                           _bounding_box[0]:(_bounding_box[0] + _bounding_box[2])]

            if coord:
                for coordinate in ast.literal_eval(coord):
                    cv2.rectangle(crop_img,
                                  (int(coordinate[0] * self.max_resolution[0]),
                                   int(coordinate[1] * self.max_resolution[1])),
                                  (int((coordinate[0] + coordinate[2]) * self.max_resolution[0]),
                                   int((coordinate[1] + coordinate[3]) * self.max_resolution[1])),
                                  (0, 255, 0),
                                  3)

            cv2.imwrite(path, crop_img)

        if self.str2bool(publish):
            msg = (
                '

'
                ''.format(link, link)
            )

            logger.info(msg, html=True)

        return path

    def _create_directory(self, path):
        target_dir = os.path.dirname(path)
        if not os.path.exists(target_dir):
            try:
                os.makedirs(target_dir)
            except OSError as exc:
                if exc.errno == errno.EEXIST and os.path.isdir(target_dir):
                    pass
                else:
                    raise

    def _get_screenshot_directory(self):

        # Use screenshot root directory if set
        if self.screenshot_root_directory is not None:
            return self.screenshot_root_directory

        # Otherwise use RF's log directory
        return self._get_log_dir()

    # should only be called by set_screenshot_directory
    def _restore_screenshot_directory(self):
        self.screenshot_root_directory = self._screenshot_path_stack.pop()

    def _get_screenshot_paths(self, filename_template):
        screenshotdir = self._get_screenshot_directory()

        filename = filename_template.format(
            index=self._get_screenshot_index(filename_template))

        # try to match {index} but not {{index}} (plus handle
        # other variants like {index!r})
        if re.search(r'(?<!{){index(![rs])?(:.*?)?}(?!})', filename_template):
            # make sure the computed filename doesn't exist. We only
            # do this if the template had the {index} formatting
            # sequence (or one of it's variations)
            while os.path.exists(os.path.join(screenshotdir, filename)):
                filename = filename_template.format(
                    index=self._get_screenshot_index(filename_template))

        filename = filename.replace('/', os.sep)
        logdir = self._get_log_dir()
        path = os.path.join(screenshotdir, filename)
        link = get_link_path(path, logdir)
        return path, link

    def _get_screenshot_index(self, filename):
        if filename not in self._screenshot_index:
            self._screenshot_index[filename] = 0
        self._screenshot_index[filename] += 1
        return self._screenshot_index[filename]

    def _get_log_dir(self):
        try:
            logfile = BuiltIn().get_variable_value('${LOG FILE}')
        except RobotNotRunningError:
            logfile = os.getcwd()
        if logfile != 'NONE':
            logdir = os.path.dirname(logfile)
        else:
            logdir = BuiltIn().get_variable_value('${OUTPUTDIR}')
        return logdir


class Solution:
    def maxEnvelopes(self, envelopes: List[List[int]]) -> int:
        def lis(nums):
            dp = [1] * len(nums)

            for i in range(len(nums)):
                for j in range(i):
                    if nums[i] > nums[j]:
                        dp[i] = max(dp[i], dp[j] + 1)

            return max(dp)

        envelopes.sort(key = lambda x: (x[0], -x[1]))

        return lis([e[1] for e in envelopes])


import sys

input = sys.stdin.readline
from collections import deque

n = 5
board = [
['R','R','R','B','B'],
['G','G','B','B','B'],
['B','B','B','R','R'],
['B','B','R','R','R'],
['R','R','R','R','R']]
dx = [0,1,0,-1]
dy = [1,0,-1,0]
rgb_visited = [[0 for _ in range(n)] for _ in range(n)]
rb_visited = [[0 for _ in range(n)] for _ in range(n)]
rgb_ans = 0
rb_ans = 0

def rgb_dfs(x,y,color):
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        if 0 <= nx < n and 0 <= ny < n and rgb_visited[nx][ny] == 0:
            if color == board[nx][ny]:
                rgb_visited[nx][ny] = 1
                rgb_dfs(nx,ny,board[nx][ny])

def rb_dfs(x,y,color):
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        if 0 <= nx < n and 0 <= ny < n and rb_visited[nx][ny] == 0:
            if color == board[nx][ny] or (color == 'R' and board[nx][ny] == 'G') or ( color == 'G' and board[nx][ny] == 'R'):
                rb_visited[nx][ny] = 1
                rb_dfs(nx,ny,board[nx][ny])

for i in range(n):
    for j in range(n):
        if rgb_visited[i][j] == 0:
            rgb_visited[i][j] = 1
            rgb_dfs(i,j,board[i][j])
            rgb_ans += 1

        if rb_visited[i][j] == 0:
            rb_visited[i][j] = 1
            rb_dfs(i,j,board[i][j])
            rb_ans += 1

print(rgb_ans,rb_ans)


import numpy as np
import itertools
from scipy.spatial.distance import cdist

def get_permutations(grid, class_num):
    n = grid[0] * grid[1]
    P_hat = np.array(list(itertools.permutations(list(range(n)), n)))

    for i in range(class_num):
        if i == 0:
            j = 0
            P = np.array(P_hat[j]).reshape([1, -1])
        else:
            P = np.concatenate([P, P_hat[j].reshape([1,-1])], axis=0)

        P_hat = np.delete(P_hat, j, axis=0)
        D = cdist(P, P_hat, metric='hamming').mean(axis=0).flatten()

        j = D.argmax()

    return P

def random_jigsaw(image, grid, permutations):
    h, w, _ = image.shape
    gh, gw = grid
    grid_h, grid_w = h // gh, w // gw

    num_class = len(permutations)
    order = np.random.randint(0, num_class)
    permutation = permutations[order]

    new_image = np.zeros_like(image)
    for i in range(gh):
        for j in range(gw):
            pos = permutation[i*gw+j]
            org_i = int(pos / gw)
            org_j = pos - org_i * gw
            new_image[i*grid_h:(i+1)*grid_h,j*grid_w:(j+1)*grid_h] = image[org_i*grid_h:(org_i+1)*grid_h,org_j*grid_w:(org_j+1)*grid_w]

    order_out = [0 for _ in range(num_class)]
    order_out[order] = 1

    return new_image, order_out

if __name__ == '__main__':
    import cv2
    from matplotlib import pyplot as plt

    grid = (3,3)
    class_num = 100
    permutations = get_permutations(grid, class_num)

    image = cv2.imread('/home/hxcai/Pictures/test/1563433082069_1_13_1.jpg')
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    image = cv2.resize(image, (192,192))

    new_image, order = random_jigsaw(image, grid, permutations)

    plt.figure(1)
    plt.imshow(image.astype(np.int32))
    plt.figure(2)
    plt.imshow(new_image.astype(np.int32))
    plt.show()

    print(order)


# 565. 数组嵌套
# 索引从0开始长度为N的数组A，包含0到N - 1的所有整数。找到最大的集合S并返回其大小，其中 S[i] = {A[i], A[A[i]], A[A[A[i]]], ... }且遵守以下的规则。

# 假设选择索引为i的元素A[i]为S的第一个元素，S的下一个元素应该是A[A[i]]，之后是A[A[A[i]]]... 以此类推，不断添加直到S出现重复的元素。

# 来源：力扣（LeetCode）
# 链接：https://leetcode.cn/problems/array-nesting
# 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。

import collections
from typing import List

class Solution:
    def arrayNesting(self, nums: List[int]) -> int:

        def find(x, vset, currMin):
            if nums[x] in vset:
                nums[x]=currMin
                return currMin
            else:
                vset.add(nums[x])
                currMin=min(nums[x],currMin)
                nums[x]=find(nums[x],vset,currMin)
            return nums[x]
        vdict=collections.defaultdict(int)
        ans = 0
        for i in range(len(nums)):
            vset = set()
            curr = len(nums)
            root = find(i,vset,curr)
            vdict[root]+=1
            if vdict[root]>ans:
                ans=vdict[root]
        return ans

class Solution2:
    def arrayNesting(self, nums: List[int]) -> int:
        vset=set()
        ans = 1
        for i in range(len(nums)):
            curr=0
            tmp = i
            while tmp not in vset:
                vset.add(tmp)
                curr+=1
                tmp=nums[tmp]
            ans = max(curr,ans)
        return ans

sol = Solution2()
nums = [5,4,0,3,1,6,2]
print(sol.arrayNesting(nums))


import common
reload(common)
from common import *

import scipy.integrate as SI
# import the usual modules
import numpy as N
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.cm as cm

kB = 8.6173324e-5 # eV/K
T  = 300 # K
beta = 1./(kB*T)

mu =   -0.40 # -400 meV

normalization = density/D_cutoff

delta = 0.010 # 50 meV

n_u   = 4001
u_max = 4.*D_cutoff
u_min =-4.*D_cutoff
d_u   = (u_max-u_min)/(n_u-1.)
iloop  = N.arange(n_u)
list_u = u_min+d_u*iloop

KK = KramersKronig(list_u)

h = 10  # figure height
w = 16  # figure width

fig1 = plt.figure(figsize=(w,h))
ax1 = fig1.add_subplot(131)
ax2 = fig1.add_subplot(132)
ax3 = fig1.add_subplot(133)

list_ax = [ax1,ax2,ax3]

ms  = 10 # marker size
mew = 2  # marker edge width
lw  = 3

gC_plus    = get_gammaC(list_u+mu+1j*delta)
gC_minus   = get_gammaC(list_u+mu-1j*delta)
KI = (gC_minus-gC_plus)/(2.*1j)
KR = (gC_minus+gC_plus)/2.

list_KK_KI = N.real(1j*KK.apply_kramers_kronig_FFT_convolution(KI))

ax1.plot(list_u,normalization*N.real(KI),'b-',lw=lw,label='$K_C^I(\epsilon+\mu)$')
ax1.plot(list_u,normalization*N.real(KR),'r-',lw=lw,label='$K_C^R(\epsilon+\mu)$')
ax1.plot(list_u,-normalization*N.real(list_KK_KI),'g--',lw=lw,label='$-KK(K_C^I(\epsilon+\mu))$')

f  = function_fermi_occupation(list_u,0.,beta)

list_FKR = f*KR
list_Fi = f*KI
list_Fr = N.real(1j*KK.apply_kramers_kronig_FFT_convolution(list_Fi))

ax2.plot(list_u,normalization*list_Fi,'b-',lw=lw,label='$f(\epsilon) K_C^I(\mu+\epsilon)$')
ax2.plot(list_u,normalization*list_Fr,'r-',lw=lw,label='$L(f(\epsilon) K_C^I(\mu+\epsilon))$')

ax3.plot(list_u,normalization*list_Fr,'r-',lw=lw,label='$L(f(\epsilon) K_C^I(\mu+\epsilon))$')
ax3.plot(list_u,normalization*list_FKR,'b-',lw=lw,label='$f(\epsilon) K_C^R(\mu+\epsilon)$')
ax3.plot(list_u,normalization*(list_Fr+list_FKR),'g--',lw=lw,label='sum')

SK = ScatteringKernel(mu,beta,delta)

filename ='scattering_spline.nc'
#SK.build_scattering_kernel()
#SK.build_and_write_spline_parameters(filename)
SK.read_spline_parameters(filename)

list_xi = N.arange(-4*D_cutoff,4*D_cutoff,0.01)
list_SK = SK.get_LC(list_xi)
list_SK2 = SK.get_L(list_xi)

#ax3.plot(SK.list_x,normalization*(SK.LC_kernel),'k--',lw=lw,label='CHECK')
ax3.plot(list_xi,normalization*(list_SK),'k--',lw=lw,label='LC')
ax3.plot(list_xi,normalization*(list_SK2),'b--',lw=lw,label='L')

def integrand(y,x):

    fy = function_fermi_occupation(N.array([y]),0.,beta)

    gC_plus    = get_gammaC(y+mu+1j*delta)
    gC_minus   = get_gammaC(y+mu-1j*delta)

    KI = (gC_minus-gC_plus)/(2.*1j)

    P  = (y-x)/((y-x)**2+delta**2)

    integrand = P/N.pi*KI*fy

    return N.real(integrand[0])

"""
list_u_small      = []
list_Fr_numerical = []
list_err = []
for u in x[::40]:

    list_u_small.append(u)
    im = SI.quad(integrand, -1.5*D_cutoff, 1.5*D_cutoff, args=(u))
    list_Fr_numerical.append(im[0])
    list_err.append(im[1])

list_u_small = N.array(list_u_small)
list_Fr_numerical = N.array(list_Fr_numerical)
ax2.plot(list_u_small,normalization*list_Fr_numerical ,'g--',lw=lw,label='$L(f K_C^I)$')
"""

for ax in list_ax:
    ax.set_xlabel('$\epsilon$ (eV)')
    ax.legend(loc=0,fancybox=True,shadow=True)
    ax.grid(True,linestyle='-',color='grey',alpha=0.5)

    ax.legend(loc=0,fancybox=True,shadow=True)

ax1.set_ylabel('$n K(\epsilon)/D$')

# adjust the figure so that there is no wasted space
fig1.suptitle('$\mu$ = %4.3f eV, $\delta$ = %4.3f eV'%(mu,delta))
fig1.subplots_adjust(   left    =   0.07,
                        bottom  =   0.15,
                        right   =   0.95,
                        top     =   0.95,
                        wspace  =   None,
                        hspace  =   None)

plt.show()


"""

    Roman Numerals Encoder

    - Create a function taking a positive integer as its parameter
    and returning a string containing the Roman Numeral representation
    of that integer.

    - Modern Roman numerals are written by expressing each digit separately
    starting with the left most digit and skipping any digit with a value of zero.

    - In Roman numerals 1990 is rendered: 1000=M, 900=CM, 90=XC; resulting in MCMXC.

    - 2008 is written as 2000=MM, 8=VIII, or MMVIII.

    - 1666 uses each Roman symbol in descending order: MDCLXVI.

    Example:

    solution(1000) -> should return 'M'

    Help:

    Value    Symbol
    1000:   'M',
    900:    'CM',
    500:    'D',
    400:    'CD',
    100:    'C',
    90:     'XC',
    50:     'L',
    40:     'XL',
    10:     'X',
    9:      'IX',
    5:      'V',
    4:      'IV',
    1:      'I'

    Remember that there can't be more than 3 identical symbols in a row.

    Task URL: https://www.codewars.com/kata/51b62bf6a9c58071c600001b

"""

def solution(number: int) -> None:

    symbol: dict[str, int] = {

        1000:   'M',
        900:    'CM',
        500:    'D',
        400:    'CD',
        100:    'C',
        90:     'XC',
        50:     'L',
        40:     'XL',
        10:     'X',
        9:      'IX',
        5:      'V',
        4:      'IV',
        1:      'I'
    }

    value = ''
    remainder = number

    for i in sorted(symbol.keys(), reverse=True):

        if remainder > 0:

            multiple = i
            roman_number = symbol[i]

            divider = remainder // multiple
            remainder = remainder % multiple

            value += roman_number * divider

    return value

print(solution(2007))


import sys

# 29200 KB / 84 ms
# input = sys.stdin.readline
sys.stdin = open('input_1431.txt')

input()  # 제출할 때 삭제
N = int(input())
s = sorted([input() for _ in range(N)])
s_sum = {key: 0 for key in s}  # 각각의 숫자합 딕셔너리

# s_sum에 숫자합 담기
for chars in s:
    for char in chars:
        if char.isdigit():
            s_sum[chars] += int(char)

for i in range(N - 1, 0, -1):  # 끝 포인트
    for j in range(i):
        if len(s[j]) > len(s[j + 1]):
            s[j], s[j + 1] = s[j + 1], s[j]
        elif len(s[j]) == len(s[j + 1]):
            if s_sum[s[j]] > s_sum[s[j + 1]]:
                s[j], s[j + 1] = s[j + 1], s[j]

for serial in s:
    print(serial)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Nov 29 15:43:33 2019

@author: ffm5105
"""
"""
Data Format:
    0: patient id
    1: claim id
    2: sex
    3: race
    4: age group
    5: location
    6: country
    7: time
    8: procedure codes
    9: diagnosis codes
"""

import pickle
import datetime
diseases = ['copd', 'hf', 'kidney', 'amnesia', 'dementias']

for disease in diseases:
    case_file = 'data/' + disease + '/' + disease + '_case_patient_data_new.txt'
    control_file = 'data/' + disease + '/' + disease + '_control_patient_data_new.txt'
    visit_file = 'data/' + disease + '/' + disease + '_visits_new.pickle'
    label_file = 'data/' + disease + '/' + disease + '_labels_new.pickle'
    identity_file = 'data/' + disease + '/' + disease + '_identity_new.pickle'
    dict_file = 'data/' + disease + '/' + disease + '_code2idx_new.pickle'
    time_file = 'data/' + disease + '/' + disease + '_times_new.pickle'
    code2id = {}
    claims = [] # patient, visit, code [patient:[visit:[codes], [codes], ...], [[],[], ...], ...]
    labels = [] # label [patient's label, label, ...]
    times = []
    identity = []
    patient_claims = {}
    patient_labels = {}
    patient_date = {}
    patient_identity = {}
    files = [control_file, case_file]
    for i in range(len(files)):
        with open(files[i], 'r') as f:
            for line in f.readlines():
                strs = line.strip().split('\t')
                #print(strs)
                pid = strs[0]
                sex = strs[2]
                race = strs[3]
                age = strs[4]
                time = strs[7]
                try:
                    datetime.datetime.strptime(time, '%Y-%m-%d')
                except:
                    print("here")
                diagnosis = strs[-1].split(',')
                if pid not in patient_claims.keys():
                    patient_claims[pid] = []
                    patient_labels[pid] = i
                    patient_date[pid] = []
                    patient_identity[pid] = [sex, race, age]

                # code to index
                binary_visit = []
                for code in diagnosis:
                    if code not in code2id.keys():
                        code2id[code] = len(code2id)
                    binary_visit.append(code2id[code])

                # visits for each patient
                patient_claims[pid].append(binary_visit)
                patient_date[pid].append(time)
    for key in patient_date.keys():
        data_list = patient_date[key]
        data_list.sort(key=lambda x:datetime.datetime.strptime(x, '%Y-%m-%d'))
        final_time = datetime.datetime.strptime(data_list[-1], '%Y-%m-%d')
        for k in range(len(patient_date[key])):
            time_now = datetime.datetime.strptime(patient_date[key][k], '%Y-%m-%d')
            delta = final_time - time_now
            patient_date[key][k] = int(delta.days)
    # all patients' data
    for pid, pclaims in patient_claims.items():
        claims.append(pclaims)
        labels.append(patient_labels[pid])
        times.append(patient_date[pid])
        identity.append(patient_identity[pid])

    # write files
    with open(visit_file, 'wb') as f:
        pickle.dump(claims, f, protocol = 0)
    with open(label_file, 'wb') as f:
        pickle.dump(labels, f, protocol = 0)
    with open(time_file, 'wb') as f:
        pickle.dump(times, f, protocol = 0)
    with open(dict_file, 'wb') as f:
        pickle.dump(code2id, f, protocol = 0)
    with open(identity_file, 'wb') as f:
        pickle.dump(identity, f, protocol = 0)


import pandas as pd
import test_groups as TG
from save_plot import insert_plot as IP
from one_limit import o_chart as OL
from two_limits_old import t_chart as TL
from mult_limits import m_chart as ML
from worder import WordPreparation

def Sorter(group_name, test_name, patient_val):
    #patient_val = patient_val.values[0] if isinstance(patient_val, pd.Series) else patient_val
    test = TG.Lead(group_name)[test_name]  # References that we are going to use, a dictionary
    lwst, bgst = min(test.values()), max(test.values())
    keylwst, keybgst = [key for key, val in test.items() if val == lwst][0], [key for key, val in test.items() if val == bgst][0]

    if lwst == bgst:
        remaining_limits = {}
        l_remaining_limits = 0
    else:
        l_remaining_limits = len(test) - 2  # Check how many reference limits we have left
        remaining_limits = test.copy()
        remaining_limits.pop(keylwst)
        remaining_limits.pop(keybgst)

    if lwst == bgst:
        ref = lwst
        constant = (3.5*ref)/7

        for key in test.keys():
            if key.find("<") == -1:
                keybgst = key
            else:
                keylwst = key
        fig = OL(patient_val, ref, keylwst, keybgst, constant)
        plot_file = f'{test_name.lower().replace(" ","_").replace("/","%")}.png'
        IP(group_name, plot_file, fig)

    elif l_remaining_limits > 0:
        constant = 2 * (abs(lwst - bgst)) / 3
        fig = ML(patient_val, lwst, bgst, keylwst, keybgst, constant, remaining_limits)
        plot_file = f'{test_name.lower().replace(" ","_").replace("/","%")}.png'
        IP(group_name, plot_file, fig)
        # send to >2 limit, needs *extra_limits
    else:
        # send to two limits, has a constant
        constant = 2 * (abs(lwst - bgst)) / 3
        fig = TL(patient_val, lwst, bgst, keylwst, keybgst, constant)
        plot_file = f'{test_name.lower().replace(" ","_").replace("/","%")}.png'
        IP(group_name, plot_file, fig)


import sys
from TreeDataView import TreeDataView
import random
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
import pyperclip

my_event = None

def main():
    root = tk.Tk()
    root.wm_title('TreeDataView as a Table')

    def copy_to_clipboard():
        global my_event
        column = tdv1.identify_column(my_event.x)
        selitem = tdv1.selection()
        if selitem:
            text = tdv1.item(selitem[0], 'values')
            cell = int(column[1]) - 1
            my_event = None
            pyperclip.copy(text[cell])
        else:
            messagebox.showwarning('Warning', 'Please make a selection and try again!')

    def double_click(event):
        rowid = tdv1.identify_row(event.y)
        column = tdv1.identify_column(event.x)
        selitems = tdv1.selection()
        if selitems:
            selitem = selitems[0]
            text = tdv1.item(selitem, 'values')
            cell = int(column[1])-1
            print('Click on row:', rowid[0])
            print('Row data:', text)
            print('Clicked on Cell:', cell)
            print('Cell data:', text[cell])

    def right_click_func():
        global my_event
        column = tdv1.identify_column(my_event.x)
        selitem = tdv1.selection()
        if selitem:
            text = tdv1.item(selitem[0], 'values')
            cell = int(column[1]) - 1
            my_event = None
            print(text)
            print(cell)
        else:
            messagebox.showwarning('Warning', 'Please make a selection and try again!')

    def popup_menu(event):
        global my_event
        my_event = event
        row_id = tdv1.identify_row(event.y)
        tdv1.selection_set(row_id)
        right_click_menu.post(event.x_root, event.y_root)

    def get_row_data():
        selected_row = tdv1.selection()
        prev_item = tdv1.prev(selected_row)
        text = tdv1.item(selected_row, 'values')
        tags = tdv1.item(prev_item, 'tags')
        if tags:
            print(tags[0])
        else:
            pass
        print(text)

    def delete_row():
        selected_row = tdv1.selection()
        tdv1.delete(selected_row)

    menu = tk.Menu(root, tearoff=0)
    menu.add_command(label='Print row', command=get_row_data)
    menu.add_command(label='Add', command=None)
    menu.add_command(label='Edit', command=None)
    menu.add_command(label='Delete', command=delete_row)

    # Right Click Pop-up Menu
    right_click_menu = tk.Menu(root, tearoff=0)
    right_click_menu.add_command(label='Copy', command=copy_to_clipboard)
    right_click_menu.add_command(label='Item1', command=right_click_func)
    right_click_menu.add_command(label='Item2', command=right_click_func)
    right_click_sub_menu = tk.Menu(right_click_menu, tearoff=0)
    right_click_menu.add_cascade(label='Sub-Menu', menu=right_click_sub_menu)
    right_click_sub_menu.add_command(label='Sub Item1', command=right_click_func)
    right_click_sub_menu.add_command(label='Sub Item2', command=right_click_func)

    def mymenu(event):
        row_id = tdv1.identify_row(event.y)
        tdv1.selection_set(row_id)
        menu.post(event.x_root, event.y_root)

    tree_columns = ['Name', 'Phone', 'Email', 'Company', 'Date']
    tdv1 = TreeDataView(root, tree_columns, scrollbar_x=True, scrollbar_y=True, double_click=double_click,
                        right_click=popup_menu)
    tdv1.pack(fill='both', expand=1)

    def insert_data():
        # Lets generate a random phone number, and a date.
        phone = '(800) {}-{}'.format(random.randint(300, 900), random.randint(5000, 9000))
        date = '{:02d}/{:02d}/{}'.format(random.randint(1, 12), random.randint(1, 31), random.randint(2010, 2017))

        # Lets pick a random name, email and company name from the lists then create the email address.
        name_list = ['Kari Turner', 'Melinda Blanks', 'Russell Wise', 'James Garcia']
        company_list = ['Mansmann', 'Merrymaking', 'Monk Real Estate']
        name = random.choice(name_list)
        company = random.choice(company_list)
        email = '{}@{}'.format(name[0].lower() + name.split()[-1].lower(), company.replace(' ', '').lower())

        # Now lets insert a row with random data into the table.
        new_item = tdv1.insert('', 'end', values=(name, phone, email, company, date))

    button1 = ttk.Button(root, text='Insert random data', command=insert_data)
    button1.pack(side='bottom')

    root.mainloop()

if __name__ == '__main__':
    main()


# type: ignore
from setuptools import find_packages, setup

requirements = [
    "scipy",
    "xarray",
    "pandas",
]

source_requirements = []

setup(
    name="pySESL",
    author="Ian Bolliger",
    description="Semi-empirical Sea Level Estimator",
    author_email="ibolliger@rhg.com",
    packages=find_packages(),
    include_package_data=True,
    install_requires=requirements,
    dependency_links=source_requirements,
)