# Bibliotecas
import pandas as pd
import datetime
import plotly.express as px
import folium
from haversine import haversine
import streamlit as st
from PIL import Image
from streamlit_folium import folium_static

# =============================================================
# Funções
# =============================================================

def carrega_dataframe():
    """ Função para carregar o dataframe para a memória

    Returns:
        dataframe: retorna dataframe com a base carregada
    """
    path = 'dados/'
    df = pd.read_csv(path + 'train.csv')
    df1 = df.copy()
    return df1

def tratamento_dataframe(df1):
    """Função para fazer o tratamento e limpeza da base de dados
    1. Retira espaços em branco das variáveis de texto
    2. Retira dados faltantes
    3. Ajusta formato das variáveis
    4. Retira texto da variável de tempo (numérica)
    5. Cria variável de semana do ano
    6. Cria variável de distância da entrega

    Args:
        df1 (dataframe): leitura do dataframe carregado na memória

    Returns:
        dataframe: retorna dataframe com todas as limpezas e tratamentos
    """

    # Retirando espaços em branco das variáveis categóricas
    df1.loc[:, 'ID'] = df1.loc[:, 'ID'].str.strip()
    df1.loc[:, 'Delivery_person_ID'] = df1.loc[:,
                                               'Delivery_person_ID'].str.strip()
    df1.loc[:, 'Road_traffic_density'] = df1.loc[:,
                                                 'Road_traffic_density'].str.strip()
    df1.loc[:, 'Type_of_order'] = df1.loc[:, 'Type_of_order'].str.strip()
    df1.loc[:, 'Type_of_vehicle'] = df1.loc[:, 'Type_of_vehicle'].str.strip()
    df1.loc[:, 'Festival'] = df1.loc[:, 'Festival'].str.strip()
    df1.loc[:, 'City'] = df1.loc[:, 'City'].str.strip()

    # Retirando dados faltantes
    df1 = df1[(df1['Delivery_person_Age'] != 'NaN ')
              & (df1['multiple_deliveries'] != 'NaN ')
              & (df1['Road_traffic_density'] != 'NaN')
              & (df1['City'] != 'NaN')
              & (df1['Weatherconditions'] != 'conditions NaN')
              & (df1['Festival'] != 'NaN')
              ].reset_index(drop=True)

    # Ajustando o formato das variáveis
    df1['Delivery_person_Age'] = df1['Delivery_person_Age'].astype('int64')
    df1['Delivery_person_Ratings'] = df1['Delivery_person_Ratings'].astype(
        float)
    df1['Order_Date'] = pd.to_datetime(df1['Order_Date'], format='%d-%m-%Y')
    df1['multiple_deliveries'] = df1['multiple_deliveries'].astype('int64')

    # Retirando texto (min) da coluna de tempo de entrega
    df1['Time_taken(min)'] = df1['Time_taken(min)'].apply(
        lambda x: x.split('(min) ')[1])
    df1['Time_taken(min)'] = df1['Time_taken(min)'].astype('int64')

    # Criando variável do dia da semana
    df1['week_of_year'] = df1['Order_Date'].dt.strftime('%U')
    df1['week_of_year'] = df1['week_of_year'].astype('int64')

    # Criando variavel de distancia
    df1['distancia'] = df1.apply(lambda x: haversine((x['Restaurant_latitude'], x['Restaurant_longitude']),
                                                     (x['Delivery_location_latitude'], x['Delivery_location_longitude'])), axis=1)

    df1 = df1.reset_index()
    df2 = df1.copy()
    return df2

df1 = carrega_dataframe()
df2 = tratamento_dataframe(df1)

# =======================================================
#  STREAMLIT
# =======================================================

# =======================================================
#  CONFIGURA PÁGINA
# =======================================================
st.set_page_config(page_title='Visão Empresa', page_icon='📈', layout="wide",
                   initial_sidebar_state="auto", menu_items=None)
st.markdown('# Cury Company - **Visão Empresa**')

# =======================================================
#  BARRA LATERAL
# =======================================================
path = ''
image = Image.open(path + 'img.jpg')
st.sidebar.image(image, width=300)
st.sidebar.markdown('# **Cury Company Delivery**🍕')

st.sidebar.markdown('---')
st.sidebar.markdown('### Selecione uma data limite')
date_slider = st.sidebar.slider('',
                                # value=datetime.datetime(2022, 4, 13),
                                value=datetime.datetime(df2['Order_Date'].max(
                                ).year, df2['Order_Date'].max().month, df2['Order_Date'].max().day),
                                min_value=datetime.datetime(df2['Order_Date'].min(
                                ).year, df2['Order_Date'].min().month, df2['Order_Date'].min().day),
                                max_value=datetime.datetime(df2['Order_Date'].max(
                                ).year, df2['Order_Date'].max().month, df2['Order_Date'].max().day),
                                format='DD-MM-YYYY')

st.sidebar.markdown('---')
st.sidebar.markdown('### Selecione as condições de trânsito')
traffic_options = st.sidebar.multiselect('',
                                         df2['Road_traffic_density'].unique(),
                                         default=df2['Road_traffic_density'].unique())

st.sidebar.markdown('---')
st.sidebar.markdown('### Selecione o tipo de veículo')
vehicle_options = st.sidebar.multiselect('',
                                         df2['Type_of_vehicle'].unique(),
                                         default=df2['Type_of_vehicle'].unique())

st.sidebar.markdown('---')
st.sidebar.markdown('### Selecione o tipo de pedido')
order_options = st.sidebar.multiselect('',
                                       df2['Type_of_order'].unique(),
                                       default=df2['Type_of_order'].unique())

st.sidebar.markdown('---')
st.sidebar.markdown('### Selecione o tipo de cidade')
city_options = st.sidebar.multiselect('',
                                      df2['City'].unique(),
                                      default=df2['City'].unique())

st.sidebar.markdown('---')
st.sidebar.markdown('### Selecione as condições climáticas')
weather_options = st.sidebar.multiselect('',
                                         df2['Weatherconditions'].unique(),
                                         default=df2['Weatherconditions'].unique())

st.sidebar.markdown('---')
st.sidebar.markdown('')
st.sidebar.markdown('##### Criado por **Adérito Bernardes**')
st.sidebar.markdown('---')

# =======================================================
#  APLICANDO FILTROS
# =======================================================

df2 = df2.loc[df2['Order_Date'] <= date_slider, :]
df2 = df2.loc[df2['Road_traffic_density'].isin(traffic_options), :]
df2 = df2.loc[df2['Type_of_vehicle'].isin(vehicle_options), :]
df2 = df2.loc[df2['Type_of_order'].isin(order_options), :]
df2 = df2.loc[df2['City'].isin(city_options), :]
df2 = df2.loc[df2['Weatherconditions'].isin(weather_options), :]

# =======================================================
#  LAYOUT STREAMLIT
# =======================================================
tab1, tab2, tab3 = st.tabs(
    ['Visão Gerencial', 'Visão Estratégica', 'Visão Geográfica'])

with tab1:
    with st.container():
        st.markdown('##### Pedidos por dia')
        df_aux = df2[['Order_Date', 'ID']].groupby(
            ['Order_Date']).count().reset_index()
        df_aux.columns = ['Order_Date', 'qtd_entregas']
        fig = px.bar(df_aux, x='Order_Date', y='qtd_entregas', labels={'Order_Date': 'Data do pedido',
                                                                       'qtd_entregas': 'Qtd entregas'
                                                                       })
        st.plotly_chart(fig, use_container_width=True)

    with st.container():
        col1, col2 = st.columns(2, gap='large')
        with col1:
            st.markdown('##### Pedidos por densidade de tráfego')
            df_aux = df2[['Road_traffic_density', 'ID']].groupby(
                ['Road_traffic_density']).count().reset_index()
            df_aux.columns = ['Road_traffic_density', 'qtd_entregas']
            df_aux['perc_ID'] = 100 * \
                (df_aux['qtd_entregas']/df_aux['qtd_entregas'].sum())
            fig = px.pie(df_aux, values='perc_ID', names='Road_traffic_density', labels={'Road_traffic_density': 'Densidade de tráfego',
                                                                                'perc_ID': '% entregas'
                                                                                })
            st.plotly_chart(fig, use_container_width=True)
        with col2:
            st.markdown('##### Pedidos por densidade de tráfego e cidade')
            df_aux = df2[['Road_traffic_density', 'City', 'ID']].groupby(
                ['City', 'Road_traffic_density']).count().reset_index()
            df_aux.columns = ['Road_traffic_density', 'City', 'qtd_entregas']
            df_aux['perc_ID'] = 100 * \
                (df_aux['qtd_entregas']/df_aux['qtd_entregas'].sum())

            fig = px.bar(df_aux, x='City', y='qtd_entregas', color='Road_traffic_density', barmode='group', labels={'Road_traffic_density': 'Densidade de tráfego',
                                                                                'City': 'Cidade',
                                                                                'qtd_entregas': 'Qtd entregas'})
            st.plotly_chart(fig, use_container_width=True)

with tab2:
    with st.container():
        st.markdown('##### Pedidos por semana')
        df_aux = df2[['week_of_year', 'ID']].groupby(
            ['week_of_year']).count().reset_index()
        df_aux.columns = ['week_of_year', 'qtd_entregas']
        fig = px.line(df_aux, x='week_of_year', y='qtd_entregas', labels={'week_of_year': 'Semana do ano',
                                                                          'qtd_entregas': 'Qtd entregas'
                                                                          })
        st.plotly_chart(fig, use_container_width=True)

    with st.container():
        st.markdown('##### Pedidos por entregador por semana')
        df_aux1 = df2.loc[:, ['ID', 'week_of_year']].groupby(
            'week_of_year').count().reset_index()
        df_aux2 = df2.loc[:, ['Delivery_person_ID', 'week_of_year']].groupby(
            'week_of_year').nunique().reset_index()
        df_aux = pd.merge(df_aux1, df_aux2, how='inner')
        df_aux['order_by_delivery'] = df_aux['ID'] / \
            df_aux['Delivery_person_ID']
        fig = px.line(df_aux, x='week_of_year', y='order_by_delivery', labels={'week_of_year': 'Semana do ano',
                                                                               'order_by_delivery': 'Pedidos por entregador'})
        st.plotly_chart(fig, use_container_width=True)

with tab3:
    st.markdown('##### Mapa geográfico das entregas')
    columns = [
        'City',
        'Road_traffic_density',
        'Delivery_location_latitude',
        'Delivery_location_longitude'
    ]

    columns_grouped = ['City', 'Road_traffic_density']
    data_plot = df2.loc[:, columns].groupby(
        columns_grouped).median().reset_index()
    data_plot.columns = [
        'Cidade', 'Densidade de tráfego', 'latitude', 'longitude']

    # Desenhar o mapa
    map_ = folium.Map(zoom_start=11)
    for index, location_info in data_plot.iterrows():
        folium.Marker([location_info['latitude'],
                       location_info['longitude']],
                      popup=location_info[['Cidade', 'Densidade de tráfego']],
                      icon=folium.Icon(color='red', icon='info-sign')).add_to(map_)
    folium_static(map_, width=1024, height=500)


# coding=utf-8
from django.conf import settings
from rest_framework import permissions
from rest_framework.decorators import api_view, permission_classes, authentication_classes
from rest_framework.response import Response
from biz.models import Message, HotVideo, GameNews, UserProfile, User, Player
from biz.redis_client import incr_number_of_share, forward_message, forward_hotvideo, follower_count, following_count
from biz.utils import get_model_class_by_name, get_share_img_url, get_object_or_404
from biz.weixin_public_client import Sign

'''
带图片（头像）、主标题（取动态文字）、副标题为 “来自xx的拳城出击”，xx为用户昵称。
主标题最多2行展示，文字过多时，以...结束。
如只有图片、视频，主标题默认为“分享XX动态“。XX为用户昵称。

如视频已付费，分享出去还是未付费的分享页。视频是不完整视频。
击xx元观看完整视频”按钮和“打开app”相同，ios打开appstore页。安卓打开下载提示页。“
热门视频分享，主标题 ：视频名称、图片 展示图片 ，副标题 拳城出击。

图文资讯-新增资讯/修改 分为 app内正文 和 app外分享正文。
app内正文必填，app外分享正文选填。如未填写app外分享正文，app内和app外分享都显示app内正文。
如有 app外分享正文，则分享后，显示app外分享正文。app内还是显示app内正文。

详情页分享设计规范
https://ad.weixin.qq.com/learn/n6
'''

h5_base_url = settings.SHARE_H5_BASE_URL

def _truncate_text(s, length):
    if len(s) <= length:
        return s
    return f'{s[:length-3]}...'

@api_view(['GET'])
@permission_classes([permissions.AllowAny])
@authentication_classes([])
def share_view(request, object_type, object_id):
    model_class = get_model_class_by_name(object_type)
    obj = get_object_or_404(model_class, pk=object_id)
    sub_title = picture = ''
    plural_prefix = 's' if object_type != 'game_news' else ''
    url = f'{h5_base_url}{object_type}{plural_prefix}/{object_id}'
    weibo = ''  # 微博分享专用字段，解决因产品需求导致分享文案不同问题
    if isinstance(obj, Message):
        user = obj.user
        title = obj.content
        if hasattr(user, 'user_profile'):
            profile = user.user_profile
            if not title:
                title = f'分享{profile.nick_name}动态'
            sub_title = f'来自拳城出击的{profile.nick_name}'
            picture = get_share_img_url(profile.avatar)
        title = _truncate_text(title, 14)
        sub_title = _truncate_text(sub_title, 20)
        forward_message(object_id)
    elif isinstance(obj, HotVideo):
        user_id = request.GET.get('user_id')
        if user_id:
            user = get_object_or_404(User, pk=user_id)
        else:
            user = obj.users.first()
        title = obj.name
        sub_title = f'来自拳城出击的热门视频'
        picture = get_share_img_url(obj.cover) or get_share_img_url(obj.try_url, is_video=True)
        url = f'{h5_base_url}hot_videos/{user.id}/{object_id}'
        forward_hotvideo(object_id)
    elif isinstance(obj, GameNews):
        title = obj.title
        sub_title = obj.sub_title
        picture = get_share_img_url(obj.picture)
        user = obj.operator
        url = f'{h5_base_url}game_news/{object_id}/0'  # 0 不在app内打开
    elif isinstance(obj, Player):
        title = f'分享{obj.user.user_profile.nick_name}的个人战绩'
        user = obj.user
        follower = follower_count(user.id)
        following = following_count(user.id)
        sub_title = f'已关注: {following}，粉丝数: {follower}'
        picture = get_share_img_url(obj.avatar)
        url = f'{h5_base_url}players/{obj.id}'
        weibo = url + f'  分享来自拳城出击的{user.user_profile.nick_name}的精彩瞬间'
    else:
        title = '我在拳城出击发现了一个很棒的拳击教练，一起去约课吧～'
        sub_title = '上拳城，玩转拳击'
        picture = get_share_img_url(UserProfile.objects.filter(user_id=obj.id).only('avatar').first().avatar)
        user = obj

    data = {
        'title': title,
        'sub_title': sub_title,
        'picture': picture,
        'url': url,
        'weibo': weibo
    }
    if user:
        incr_number_of_share(user.id)
    return Response(data)

@api_view(['GET'])
@authentication_classes([])
@permission_classes([])
def second_share_signature(request):
    url = request.query_params.get("url", "")
    return Response(Sign(url).sign())


# coding: utf-8

# In[1]:

get_ipython().run_line_magic('matplotlib', 'inline')
get_ipython().run_line_magic('reload_ext', 'autoreload')
get_ipython().run_line_magic('autoreload', '2')

# In[2]:

from fastai.conv_learner import *
from fastai.dataset import *
from fastai.transforms import *
from fastai.models.resnet import vgg_resnet50
from sklearn.metrics import roc_auc_score
import pixiedust
from matplotlib.patches import Rectangle

# In[3]:

PATH = Path('/mnt/data/xray-thesis/data/chestX-ray14')
IMAGE_DN = 'images'
TRAIN_CSV = 'train_list.csv'
TEST_CSV = 'test_list.csv'
sz = 224
bs = 64
arch = resnet50
N_CLASSES = 15

# ## Load dataset

# In[4]:

def aucs(targets, preds):
    aurocs = []
    for i in range(N_CLASSES):
        aurocs.append(roc_auc_score(targets[:, i], preds[:, i]))
    return aurocs

# In[5]:

aug_tmfs = [RandomFlip(),
            RandomCrop(sz)]
tmfs = tfms_from_model(arch, sz, aug_tmfs, 1.05)
md = ImageClassifierData.from_csv(PATH, 'images', PATH/TRAIN_CSV, bs, tmfs, cat_separator='|')

# In[6]:

x, y = next(iter(md.val_dl))

# ## Densenet121 arch with binary classification

# In[6]:

class LSEPool2d(nn.Module):

    def __init__(self, r=3):
        super().__init__()
        self.r =r

    def forward(self, x):
        s = x.size()[3]  # x: bs*2048*7*7
        r = self.r
        x_max = F.adaptive_max_pool2d(x, 1) # x_max: bs*2048*1*1
        p = ((1/r) * torch.log((1 / (s*s)) * torch.exp(r*(x - x_max)).sum(3).sum(2)))
        x_max = x_max.view(x.size(0), -1) # bs*2048
        return x_max+p

head = nn.Sequential(LSEPool2d(),
                     Flatten(),
                     nn.Linear(2048, 15),
                     nn.Sigmoid())

# In[7]:

models = ConvnetBuilder(arch, 0, 0, 0, custom_head=head)
learn = ConvLearner(md, models)
learn.crit = nn.BCELoss()

# In[8]:

learn.summary()

# In[71]:

learn.freeze_to(-1)
learn.lr_find()

# In[66]:

learn.sched.plot(0, 0)

# In[72]:

lr = 1e-2
learn.fit(lr, 3)

# In[67]:

# py, y = learn.TTA()

# In[75]:

# y.shape, .shape
aucs = aucs(y, np.mean(py, axis=0))
np.mean(aucs)

# In[92]:

learn.save('tmp')

# In[8]:

learn.load('tmp')

# ## Class Activation Map

# In[ ]:

x, y = next(iter(md.val_dl))
x, y = x[None, 1], y[None, 1]

# In[33]:

class FeatureHook:
    features = None

    def __init__(self, m):
        self.hook = m.register_forward_hook(self.hook_fn)

    def hook_fn(self, module, input, output):
        self.features = output

    def remove(self):
        self.hook.remove()

class WeightHook:
    weights = None

    def __init__(self, m):
        self.hook = m.register_forward_hook(self.hook_fn)

    def hook_fn(self, module, input, output):
        self.weights = list(module.parameters())[0].data

    def remove(self):
        self.hook.remove()

last_conv_layer = learn[-2][-1]
linear_layer = learn[-1][2]
feat = FeatureHook(last_conv_layer)
weig = WeightHook(linear_layer)

py = learn.model(x)

feat.remove()
weig.remove()

# In[64]:

learn[-2][-1]

# In[42]:

feat.features.shape, weig.weights.shape

# In[46]:

feat.features[0]
i = y.argmax()
f2 = np.dot(np.rollaxis(to_np(feat.features[0]), 0, 3), to_np(weig.weights[i]))
f2 -= f2.min()
f2 /= f2.max()
# get the CAM for correct class
plt.imshow(md.val_ds.denorm(x)[0])
plt.imshow(cv2.resize(f2, (224, 224)), alpha=0.5, cmap='hot')

# In[29]:

get_ipython().run_line_magic('who', 'FeatureHook')

# In[32]:

get_ipython().run_line_magic('reset_selective', '-f weig')

# ## Activation Heat Map

# In[62]:

H = torch.max(feat.features[0], dim=0)
plt.imshow(md.val_ds.denorm(x)[0])
plt.imshow(cv2.resize(to_np(H[0]), (224, 224)), alpha=0.5, cmap='hot')
feat.features[0]

# In[60]:

theta = .7
slice_x, slice_y = ndimage.find_objects(h[0] > theta, True)[0]
H[0]
rect = Rectangle(xy, width, height, linewidth=1,edgecolor='r',facecolor='none')

# plt.imshow(, (224, 224)))

# ## Knn for similar image

# ## Focal loss


"""
CS4701 Practicum in AI
Project: Checkers AI with minimax algorithm
Team members: Shunqi Mao, Pu Zhao
"""

import copy
import math
import random
import datetime
import tkinter
import _thread

class AIPlayer():
    def __init__(self, game, difficulty):
        self.game = game
        self.difficulty = difficulty

    def getNextMove(self):
        if self.difficulty == 1:
            return self.getNextMoveEasy()
        elif self.difficulty == 2:
            return self.getNextMoveMedium()
        elif self.difficulty == 3:
            return self.getNextMoveHard()
        else:
            return self.getNextMoveInfernal()

    # Simple AI, returns a random legal move
    def getNextMoveEasy(self):
        state = AIGameState(self.game)
        moves = state.getActions(False)
        index = random.randrange(len(moves))
        chosenMove = moves[index]
        return chosenMove[0], chosenMove[1], chosenMove[2], chosenMove[3]

    # Hard AI, returns the move found by alpha-beta search with depth limit 5
    def getNextMoveMedium(self):
        state = AIGameState(self.game)
        nextMove = self.alphaBetaSearch(state, 5)
        return nextMove[0], nextMove[1], nextMove[2], nextMove[3]

    # Hard AI, returns the move found by alpha-beta search with depth limit 10
    def getNextMoveHard(self):
        state = AIGameState(self.game)
        nextMove = self.alphaBetaSearch(state, 10)
        return nextMove[0], nextMove[1], nextMove[2], nextMove[3]

    # Infernal AI, returns the best move found by alpha-beta search
    def getNextMoveInfernal(self):
        state = AIGameState(self.game)
        depthLimit = self.computeDepthLimit(state)
        nextMove = self.alphaBetaSearch(state, depthLimit)
        return nextMove[0], nextMove[1], nextMove[2], nextMove[3]

    # Dynamically compute depth limit
    # Fewer checkers we have, deeper level we can search
    def computeDepthLimit(self, state):
        numcheckers = len(state.AIpieces) + len(state.humanPieces)
        return 26 - numcheckers

    def alphaBetaSearch(self, state, depthLimit):
        # collect statistics for the search
        self.currDepth = 0
        self.maxDepth = 0
        self.numNodes = 0
        self.maxPruning = 0
        self.minPruning = 0

        self.bestMove = []
        self.depthLimit = depthLimit

        starttime = datetime.datetime.now()
        v = self.maxValue(state, -1000, 1000, self.depthLimit)

        # print statistics for the search

        print("Time = " + str(datetime.datetime.now() - starttime))
        print("selected value " + str(v))
        print("(1) max depth of the tree = {0:d}".format(self.maxDepth))
        print("(2) total number of nodes generated = {0:d}".format(self.numNodes))
        print("(3) number of times pruning occurred in the MAX-VALUE() = {0:d}".format(self.maxPruning))
        print("(4) number of times pruning occurred in the MIN-VALUE() = {0:d}".format(self.minPruning))

        return self.bestMove

    # For AI player (MAX AGENT)
    def maxValue(self, state, alpha, beta, depthLimit):
        if state.terminalTest():
            return state.computeUtilityValue()
        if depthLimit == 0:
            return state.computeHeuristic()

        # update statistics for the search
        self.currDepth += 1
        self.maxDepth = max(self.maxDepth, self.currDepth)
        self.numNodes += 1

        v = -math.inf
        for a in state.getActions(False):
            # return captured checker if it is a capture move
            captured = state.applyAction(a)
            # state.printBoard()
            if state.humanCanContinue():
                next = self.minValue(state, alpha, beta, depthLimit - 1)
            else:  # human cannot move, AI gets one more move
                next = self.maxValue(state, alpha, beta, depthLimit - 1)
            if next > v:
                v = next
                # Keep track of the best move so far at the top level
                if depthLimit == self.depthLimit:
                    self.bestMove = a
            state.revoke(a, captured)

            # alpha-beta max pruning
            if v >= beta:
                self.maxPruning += 1
                self.currDepth -= 1
                return v
            alpha = max(alpha, v)

        self.currDepth -= 1

        return v

    # For human player (MIN AGENT)
    def minValue(self, state, alpha, beta, depthLimit):
        if state.terminalTest():
            return state.computeUtilityValue()
        if depthLimit == 0:
            return state.computeHeuristic()

        # update statistics for the search
        self.currDepth += 1
        self.maxDepth = max(self.maxDepth, self.currDepth)
        self.numNodes += 1

        v = math.inf
        for a in state.getActions(True):
            captured = state.applyAction(a)
            if state.AICanContinue():
                next = self.maxValue(state, alpha, beta, depthLimit - 1)
            else:  # AI cannot move, human gets one more move
                next = self.minValue(state, alpha, beta, depthLimit - 1)
            if next < v:
                v = next
            state.revoke(a, captured)

            #alpha-beta min pruning
            if v <= alpha:
                self.minPruning += 1
                self.currDepth -= 1
                return v
            beta = min(beta, v)

        self.currDepth -= 1
        return v

# a class for AI to simulate game state
class AIGameState():
    def __init__(self, game):
        self.board = copy.deepcopy(game.getBoard())

        self.AIpieces = set()
        for checker in game.opponentPieces:
            self.AIpieces.add(checker)
        self.humanPieces = set()
        for checker in game.playerPieces:
            self.humanPieces.add(checker)
        self.checkerPositions = {}
        for checker, position in game.checkerPositions.items():
            self.checkerPositions[checker] = position

    # Check if the human player can cantinue.
    def humanCanContinue(self):
        directions = [[-1, -1], [-1, 1], [-2, -2], [-2, 2]]
        for checker in self.humanPieces:
            position = self.checkerPositions[checker]
            row = position[0]
            col = position[1]
            for dir in directions:
                if self.isValidMove(row, col, row + dir[0], col + dir[1], True):
                    return True
        return False

    # Check if the AI player can cantinue.
    def AICanContinue(self):
        directions = [[1, -1], [1, 1], [2, -2], [2, 2]]
        for checker in self.AIpieces:
            position = self.checkerPositions[checker]
            row = position[0]
            col = position[1]
            for dir in directions:
                if self.isValidMove(row, col, row + dir[0], col + dir[1], False):
                    return True
        return False

    # Neither player can can continue, thus game over
    def terminalTest(self):
        if len(self.humanPieces) == 0 or len(self.AIpieces) == 0:
            return True
        else:
            return (not self.AICanContinue()) and (not self.humanCanContinue())

    # Check if current move is valid
    def isValidMove(self, oldrow, oldcol, row, col, humanTurn):
        # invalid index
        if oldrow < 0 or oldrow > 7 or oldcol < 0 or oldcol > 7 \
                or row < 0 or row > 7 or col < 0 or col > 7:
            return False
        # No checker exists in original position
        if self.board[oldrow][oldcol] == 0:
            return False
        # Another checker exists in destination position
        if self.board[row][col] != 0:
            return False

        # human player's turn
        if humanTurn:
            if row - oldrow == -1:   # regular move
                return abs(col - oldcol) == 1
            elif row - oldrow == -2:  # capture move
                return (col - oldcol == -2 and self.board[row+1][col+1] < 0) \
                       or (col - oldcol == 2 and self.board[row+1][col-1] < 0)
            else:
                return False
        # opponent's turn
        else:
            if row - oldrow == 1:   # regular move
                return abs(col - oldcol) == 1
            elif row - oldrow == 2: # capture move
                # / direction or \ direction
                return (col - oldcol == -2 and self.board[row-1][col+1] > 0) \
                       or (col - oldcol == 2 and self.board[row-1][col-1] > 0)
            else:
                return False

    # compute utility value of terminal state
    # utility value = difference in # of checkers * 500 + # of AI checkers * 50
    # utility value has larger weights so that is it preferred over heuristic values
    def computeUtilityValue(self):
        utility = (len(self.AIpieces) - len(self.humanPieces)) * 500 \
                  + len(self.AIpieces) * 50
        return utility

    # compute heuristic value of a non-terminal state
    # heuristic value = diff in # of checkers * 50 + # of safe checkers * 10 + # of AI checkers
    def computeHeuristic(self):
        heurisitc = (len(self.AIpieces) - len(self.humanPieces)) * 50 \
                    + self.countSafeAIpieces() * 10 + len(self.AIpieces)
        return heurisitc

    # Count the number of safe AI checker.
    # A safe AI checker is one checker that no opponent can capture.
    def countSafeAIpieces(self):
        count = 0
        for AIchecker in self.AIpieces:
            AIrow = self.checkerPositions[AIchecker][0]
            AIcol = self.checkerPositions[AIchecker][1]
            safe = True
            if not (AIcol == 0 or AIcol == len(self.board[0])):
                # checkers near the boundaries are safe
                for humanchecker in self.humanPieces:
                    if AIrow < self.checkerPositions[humanchecker][0]:
                        safe = False
                        break
            if safe:
                count += 1
        return count

    # get all possible actions for the current player
    def getActions(self, humanTurn):
        if humanTurn:
            checkers = self.humanPieces
            regularDirs = [[-1, -1], [-1, 1]]
            captureDirs = [[-2, -2], [-2, 2]]
        else:
            checkers = self.AIpieces
            regularDirs = [[1, -1], [1, 1]]
            captureDirs = [[2, -2], [2, 2]]

        regularMoves = []
        captureMoves = []
        for checker in checkers:
            oldrow = self.checkerPositions[checker][0]
            oldcol = self.checkerPositions[checker][1]
            for dir in regularDirs:
                if self.isValidMove(oldrow, oldcol, oldrow+dir[0], oldcol+dir[1], humanTurn):
                    regularMoves.append([oldrow, oldcol, oldrow+dir[0], oldcol+dir[1]])
            for dir in captureDirs:
                if self.isValidMove(oldrow, oldcol, oldrow+dir[0], oldcol+dir[1], humanTurn):
                    captureMoves.append([oldrow, oldcol, oldrow+dir[0], oldcol+dir[1]])

        # must take capture move if possible
        if captureMoves:
            return captureMoves
        else:
            return regularMoves

    # Apply given action to the game board.
    def applyAction(self, action):
        oldrow = action[0]
        oldcol = action[1]
        row = action[2]
        col = action[3]
        captured = 0

        # move the checker
        toMove = self.board[oldrow][oldcol]
        self.checkerPositions[toMove] = (row, col)
        self.board[row][col] = toMove
        self.board[oldrow][oldcol] = 0

        # capture move, remove captured checker
        if abs(oldrow - row) == 2:
            captured = self.board[(oldrow + row) // 2][(oldcol + col) // 2]
            if captured > 0:
                self.humanPieces.remove(captured)
            else:
                self.AIpieces.remove(captured)
            self.board[(oldrow + row) // 2][(oldcol + col) // 2] = 0
            self.checkerPositions.pop(captured, None)

        return captured

    # Reset given action to the game board. Restored captured checker if any.
    def revoke(self, action, captured):
        oldrow = action[0]
        oldcol = action[1]
        row = action[2]
        col = action[3]

        # move the checker
        toMove = self.board[row][col]
        self.checkerPositions[toMove] = (oldrow, oldcol)
        self.board[oldrow][oldcol] = toMove
        self.board[row][col] = 0

        # capture move, remove captured checker
        if abs(oldrow - row) == 2:
            if captured > 0:
                self.humanPieces.add(captured)
            else:
                self.AIpieces.add(captured)
            self.board[(oldrow + row) // 2][(oldcol + col) // 2] = captured
            self.checkerPositions[captured] = ((oldrow + row) // 2, (oldcol + col) // 2)

    def printBoard(self):
        for i in range(len(self.board)):
            for j in range(len(self.board[i])):
                check = self.board[i][j]
                if (check < 0):
                    print(check,end=' ')
                else:
                    print(' ' + str(check),end=' ')

            print()
        print('------------------------')

class CheckerGame():
    def __init__(self):
        self.lock = _thread.allocate_lock()
        self.board = self.initBoard()
        self.playerTurn = self.whoGoFirst()
        self.difficulty = self.getDifficulty()
        self.AIPlayer = AIPlayer(self, self.difficulty)
        self.GUI = BoardGUI(self)

        # AI goes first
        if not self.isPlayerTurn():
            _thread.start_new_thread(self.AIMakeMove, ())

        self.GUI.startGUI()

    # Let player decide to go first or second
    def whoGoFirst(self):
        ans = input("Do you want to go first? (Y/N) ")
        return ans == "Y" or ans == "y"

    # Let player decide level of difficulty
    def getDifficulty(self):
        ans = eval(input("What level of difficulty? (1 Easy, 2 Medium, 3 Hard, 4 Infernal) "))
        while not (ans == 1 or ans == 2 or ans == 3 or ans == 4):
            print("Invalid input, please enter a value between 1 and 4")
            ans = eval(input("What level of difficulty? (1 Easy, 2 Medium, 3 Hard) "))
        return ans

    # This function initializes the game board.
    # Each checker has a label. Positive checkers for the player,
    # and negative checkers for the opponent.
    def initBoard(self):
        board = [[0]*8 for _ in range(8)]
        self.playerPieces = set()
        self.opponentPieces = set()
        self.checkerPositions = {}
        for i in range(8):
            self.playerPieces.add(i + 1)
            self.opponentPieces.add(-(i + 1))
            if i % 2 == 0:
                board[1][i] = -(i + 1)
                board[7][i] = i + 1
                self.checkerPositions[-(i + 1)] = (1, i)
                self.checkerPositions[i + 1] = (7, i)
            else:
                board[0][i] = -(i + 1)
                board[6][i] = i + 1
                self.checkerPositions[-(i + 1)] = (0, i)
                self.checkerPositions[i + 1] = (6, i)

        self.boardUpdated = True

        return board

    def getBoard(self):
        return self.board

    def printBoard(self):
        for i in range(len(self.board)):
            for j in range(len(self.board[i])):
                check = self.board[i][j]
                if (check < 0):
                    print(check,end=' ')
                else:
                    print(' ' + str(check),end=' ')

            print()

    def isBoardUpdated(self):
        return self.boardUpdated

    def setBoardUpdated(self):
        self.lock.acquire()
        self.boardUpdated = True
        self.lock.release()

    def completeBoardUpdate(self):
        self.lock.acquire()
        self.boardUpdated = False
        self.lock.release()

    def isPlayerTurn(self):
        return self.playerTurn

    # Switch turns between player and opponent.
    # If one of them has no legal moves, the other can keep playing
    def changePlayerTurn(self):
        if self.playerTurn and self.opponentCanContinue():
            self.playerTurn = False
        elif not self.playerTurn and self.playerCanContinue():
            self.playerTurn = True

    # apply the given move in the game
    def move(self, oldrow, oldcol, row, col):
        if not self.isValidMove(oldrow, oldcol, row, col, self.playerTurn):
            return

        # human player can only choose from the possible actions
        if self.playerTurn and not ([oldrow, oldcol, row, col] in self.getPossiblePlayerActions()):
            return

        self.makeMove(oldrow, oldcol, row, col)
        _thread.start_new_thread(self.next, ())

    # update game state
    def next(self):
        if self.isGameOver():
            self.getGameSummary()
            return
        self.changePlayerTurn()
        if self.playerTurn:     # let player keep going
            return
        else:                   # AI's turn
            self.AIMakeMove()

    # Temporarily Pause GUI and ask AI player to make next move.
    def AIMakeMove(self):
        self.GUI.pauseGUI()
        oldrow, oldcol, row, col = self.AIPlayer.getNextMove()
        self.move(oldrow, oldcol, row, col)
        self.GUI.resumeGUI()

    # update checker position
    def makeMove(self, oldrow, oldcol, row, col):
        toMove = self.board[oldrow][oldcol]
        self.checkerPositions[toMove] = (row, col)

        # move the checker
        self.board[row][col] = self.board[oldrow][oldcol]
        self.board[oldrow][oldcol] = 0

        # capture move, remove captured checker
        if abs(oldrow - row) == 2:
            toRemove = self.board[(oldrow + row) // 2][(oldcol + col) // 2]
            if toRemove > 0:
                self.playerPieces.remove(toRemove)
            else:
                self.opponentPieces.remove(toRemove)
            self.board[(oldrow + row) // 2][(oldcol + col) // 2] = 0
            self.checkerPositions.pop(toRemove, None)

        self.setBoardUpdated()

    # Get all possible moves for the current player
    def getPossiblePlayerActions(self):
        checkers = self.playerPieces
        regularDirs = [[-1, -1], [-1, 1]]
        captureDirs = [[-2, -2], [-2, 2]]

        regularMoves = []
        captureMoves = []
        for checker in checkers:
            oldrow = self.checkerPositions[checker][0]
            oldcol = self.checkerPositions[checker][1]
            for dir in regularDirs:
                if self.isValidMove(oldrow, oldcol, oldrow+dir[0], oldcol+dir[1], True):
                    regularMoves.append([oldrow, oldcol, oldrow+dir[0], oldcol+dir[1]])
            for dir in captureDirs:
                if self.isValidMove(oldrow, oldcol, oldrow+dir[0], oldcol+dir[1], True):
                    captureMoves.append([oldrow, oldcol, oldrow+dir[0], oldcol+dir[1]])

        # must take capture move if possible
        if captureMoves:
            return captureMoves
        else:
            return regularMoves

    # check if the given move is valid for the current player
    def isValidMove(self, oldrow, oldcol, row, col, playerTurn):
        # invalid index
        if oldrow < 0 or oldrow > 7 or oldcol < 0 or oldcol > 7 \
                or row < 0 or row > 7 or col < 0 or col > 7:
            return False
        # No checker exists in original position
        if self.board[oldrow][oldcol] == 0:
            return False
        # Another checker exists in destination position
        if self.board[row][col] != 0:
            return False

        # player's turn
        if playerTurn:
            if row - oldrow == -1:   # regular move
                return abs(col - oldcol) == 1
            elif row - oldrow == -2:  # capture move
                #  \ direction or / direction
                return (col - oldcol == -2 and self.board[row+1][col+1] < 0) \
                       or (col - oldcol == 2 and self.board[row+1][col-1] < 0)
            else:
                return False
        # opponent's turn
        else:
            if row - oldrow == 1:   # regular move
                return abs(col - oldcol) == 1
            elif row - oldrow == 2: # capture move
                # / direction or \ direction
                return (col - oldcol == -2 and self.board[row-1][col+1] > 0) \
                       or (col - oldcol == 2 and self.board[row-1][col-1] > 0)
            else:
                return False

    # Check if the player can cantinue
    def playerCanContinue(self):
        directions = [[-1, -1], [-1, 1], [-2, -2], [-2, 2]]
        for checker in self.playerPieces:
            position = self.checkerPositions[checker]
            row = position[0]
            col = position[1]
            for dir in directions:
                if self.isValidMove(row, col, row + dir[0], col + dir[1], True):
                    return True
        return False

    # Check if the opponent can cantinue
    def opponentCanContinue(self):
        directions = [[1, -1], [1, 1], [2, -2], [2, 2]]
        for checker in self.opponentPieces:
            position = self.checkerPositions[checker]
            row = position[0]
            col = position[1]
            for dir in directions:
                if self.isValidMove(row, col, row + dir[0], col + dir[1], False):
                    return True
        return False

    # Neither player can can continue, thus game over
    def isGameOver(self):
        if len(self.playerPieces) == 0 or len(self.opponentPieces) == 0:
            return True
        else:
            return (not self.playerCanContinue()) and (not self.opponentCanContinue())

    def getGameSummary(self):
        self.GUI.pauseGUI()
        print("Game Over!")
        playerNum = len(self.playerPieces)
        opponentNum = len(self.opponentPieces)
        if (playerNum > opponentNum):
            print("Player won by {0:d} checkers! Congratulation!".format(playerNum - opponentNum))
        elif (playerNum < opponentNum):
            print("Computer won by {0:d} checkers! Try again!".format(opponentNum - playerNum))
        else:
            print("It is a draw! Try again!")

class BoardGUI():
    def __init__(self, game):
        # Initialize parameters
        self.game = game
        self.ROWS = 8
        self.COLS = 8
        self.WINDOW_WIDTH = 800
        self.WINDOW_HEIGHT = 800
        self.col_width = self.WINDOW_WIDTH / self.COLS
        self.row_height = self.WINDOW_HEIGHT / self.ROWS

        # Initialize GUI
        self.initBoard()

    def initBoard(self):
        self.root = tkinter.Tk()
        self.c = tkinter.Canvas(self.root, width=self.WINDOW_WIDTH, height=self.WINDOW_HEIGHT,
                                borderwidth=5, background='white')
        self.c.pack()
        self.board = [[0]*self.COLS for _ in range(self.ROWS)]
        self.tiles = [[None for _ in range(self.COLS)] for _ in range(self.ROWS)]

        # Print dark square
        for i in range(8):
            for j in range(8):
                if (i + j) % 2 == 1:
                    self.c.create_rectangle(i * self.row_height, j * self.col_width,
                                        (i+1) * self.row_height, (j+1) * self.col_width, fill="gray", outline="gray")

        # Print grid lines
        for i in range(8):
            self.c.create_line(0, self.row_height * i, self.WINDOW_WIDTH, self.row_height * i, width=2)
            self.c.create_line(self.col_width * i, 0, self.col_width * i, self.WINDOW_HEIGHT, width=2)

        # Place checks on the board
        self.updateBoard()

        # Initialize parameters
        self.checkerSelected = False
        self.clickData = {"row": 0, "col": 0, "checker": None}

        # Register callback function for mouse clicks
        self.c.bind("<Button-1>", self.processClick)

        # make GUI updates board every second
        self.root.after(1000, self.updateBoard)

    def startGUI(self):
        self.root.mainloop()

    def pauseGUI(self):
        self.c.bind("<Button-1>", '')

    def resumeGUI(self):
        self.c.bind("<Button-1>", self.processClick)

    # Update the positions of checkers
    def updateBoard(self):
        if self.game.isBoardUpdated():
            newBoard = self.game.getBoard()
            for i in range(len(self.board)):
                for j in range(len(self.board[0])):
                    if self.board[i][j] != newBoard[i][j]:
                        self.board[i][j] = newBoard[i][j]
                        self.c.delete(self.tiles[i][j])
                        self.tiles[i][j] = None

                        # choose different color for different player's checkers
                        if newBoard[i][j] < 0:
                            self.tiles[i][j] = self.c.create_oval(j*self.col_width+10, i*self.row_height+10,
                                                              (j+1)*self.col_width-10, (i+1)*self.row_height-10,
                                                              fill="black")
                        elif newBoard[i][j] > 0:
                            self.tiles[i][j] = self.c.create_oval(j*self.col_width+10, i*self.row_height+10,
                                                                  (j+1)*self.col_width-10, (i+1)*self.row_height-10,
                                                                  fill="red")
                        else:  # no checker
                            continue

                        # raise the tiles to highest layer
                        self.c.tag_raise(self.tiles[i][j])

            # tell game logic that GUI has updated the board
            self.game.completeBoardUpdate()

        # make GUI updates board every second
        self.root.after(1000, self.updateBoard)

    # this function checks if the checker belongs to the current player
    def isCurrentPlayerChecker(self, row, col):
        return self.game.isPlayerTurn() == (self.board[row][col] > 0)

    # callback function that process user's mouse clicks
    def processClick(self, event):
        col = int(event.x // self.col_width)
        row = int(event.y // self.row_height)

        # If there is no checker being selected
        if not self.checkerSelected:
            # there exists a checker at the clicked position
            # and the checker belongs to the current player
            if self.board[row][col] != 0 and self.isCurrentPlayerChecker(row, col):
                self.clickData["row"] = row
                self.clickData["col"] = col
                self.clickData["color"] = self.c.itemcget(self.tiles[row][col], 'fill')

                # replace clicked checker with a temporary checker
                self.c.delete(self.tiles[row][col])
                self.tiles[row][col] = self.c.create_oval(col*self.col_width+10, row*self.row_height+10,
                                                         (col+1)*self.col_width-10, (row+1)*self.row_height-10,
                                                          fill="green")
                self.checkerSelected = True

            else: # no checker at the clicked postion
                return

        else: # There is a checker being selected
            # First reset the board
            oldrow = self.clickData["row"]
            oldcol = self.clickData["col"]
            self.c.delete(self.tiles[oldrow][oldcol])
            self.tiles[oldrow][oldcol] = self.c.create_oval(oldcol*self.col_width+10, oldrow*self.row_height+10,
                                                            (oldcol+1)*self.col_width-10, (oldrow+1)*self.row_height-10,
                                                            fill=self.clickData["color"])

            # If the destination leads to a legal move
            self.game.move(self.clickData["row"], self.clickData["col"],row, col)
            self.checkerSelected = False

game = CheckerGame()


import asyncio
import socketio
from services.redis import redis_m

sio = socketio.AsyncClient()  # instance of socket io server

@sio.event
async def send_message(message):
    '''Send message to the room from connected client.'''
    print(f'Sending: {message}')
    await sio.send(message)

@sio.event
async def connect():
    '''Connect to the selected room and print "connection established" message
    to client.'''
    print('connection established')
    await sio.emit('rooms', {'room': 'Redis_Room'})

@sio.event
async def disconnect():
    '''Disconnect message when server disconnect client'''
    print('disconnected from server')

async def main():
    await sio.connect('http://localhost:8080')
    while True:
        try:
            await send_message(redis_m.decode())
            await sio.sleep(60)
        except KeyboardInterrupt:
            break
    await sio.wait()

if __name__ == '__main__':
    asyncio.run(main())


from __future__ import print_function
import numpy as np
import matplotlib.pyplot as plt

# height (cm), input data, each row is a data point
X = np.array([[147, 150, 153, 158, 163, 165, 168, 170, 173, 175, 178, 180, 183]]).T

# weight (kg)
y = np.array([49, 50, 51, 54, 58, 59, 60, 62, 63, 64, 66, 67, 68])

# weight = w_1 * height + w_0

# Building Xbar
one = np.ones((X.shape[0], 1))
Xbar = np.concatenate((one, X), axis = 1) # each row is one data point
# Calculating weights of the linear regression model
A = np.dot(Xbar.T, Xbar)
b = np.dot(Xbar.T, y)
w = np.dot(np.linalg.pinv(A), b)

# weights
w_0, w_1 = w[0], w[1]

y1 = w_1 * 155 + w_0
y2 = w_1 * 160 + w_0

print('Input 155cm, true output 52kg, predicted output %.2fkg.' %(y1))
print('Input 160cm, true output 56kg, predicted output %.2fkg.' %(y2))

print()
print('Using scikit-learn')
from sklearn import datasets, linear_model
#fit the model Linear Regression
regr = linear_model.LinearRegression()
regr.fit(X, y)  # in scikit-learn, each sample is one row
# Compare two results
print("scikit-learn's solution: w_1 = ", regr.coef_[0], "w_0 = ", regr.intercept_)
print("our solution           : w_1 = ", w[1], "w_0 = ", w[0])


import multiprocessing
import random
import sys
import threading
from multiprocessing.synchronize import Lock
from scalene.scalene_profiler import Scalene
from typing import Any

def _recreate_replacement_sem_lock():
    return ReplacementSemLock()

class ReplacementSemLock(multiprocessing.synchronize.Lock):
    def __init__(self, ctx=None):
        # Ensure to use the appropriate context while initializing
        if ctx is None:
            ctx = multiprocessing.get_context()
        super().__init__(ctx=ctx)
    def __enter__(self) -> bool:
        max_timeout = sys.getswitchinterval()
        tident = threading.get_ident()
        while True:
            Scalene.set_thread_sleeping(tident)
            timeout = random.random() * max_timeout
            acquired = self._semlock.acquire(timeout=timeout)  # type: ignore
            Scalene.reset_thread_sleeping(tident)
            if acquired:
                return True
            else:
                max_timeout *= 2 # Exponential backoff
    def __exit__(self, *args: Any) -> None:
        super().__exit__(*args)
    def __reduce__(self):
        return (_recreate_replacement_sem_lock, ())


"""Extends OpenAPI to add enriched documentation"""

import logging

from eguivalet_server.config import CODE_EXAMPLES, LABEL_LANG_MAPPING

logger = logging.getLogger(__name__)

def add_examples(openapi_schema: dict, docs_dir=CODE_EXAMPLES) -> dict:
    """Adds code examples to the Redoc interface"""

    path_key = 'paths'
    code_key = 'x-codeSamples'

    for folder in docs_dir.iterdir():
        if folder.is_file():
            continue
        files = [f for f in folder.iterdir() if f.is_file()]
        for file in files:
            parts = file.name.split('-')
            if len(parts) >= 1:
                route = '/'
                if len(parts) >= 2:
                    route += '/'.join(parts[:-1])
                    if not parts[-2].endswith('}'):
                        route += '/'
                method = parts[-1].split('.')[0]
                logger.info(
                    "[%s][%s][%s][%s]",
                    path_key, route, method, code_key
                )

                if route in openapi_schema[path_key]:
                    if code_key not in openapi_schema[path_key][route][method]:
                        openapi_schema[path_key][route][method].update({code_key: []})

                    openapi_schema[path_key][route][method][code_key].append({
                        'lang': LABEL_LANG_MAPPING[folder.name],
                        'source': file.read_text(),
                        'label': LABEL_LANG_MAPPING[folder.name]
                    })
                else:
                    logger.error("Error adding code example to OpenAPI; %s", file)

    return openapi_schema


from typing import List

def gen_columns(num_colors_per_row: int) -> List[str]:
    channels_map = ("red", "blue", "green")
    number_channels = 3

    columns = list()

    for i in range(num_colors_per_row * number_channels):
        c_name = f"{channels_map[i % number_channels]}{i // 3}"
        columns.append(c_name)

    return columns


#!/usr/bin/python
#Gonzalo Figueroa del Val

from pyspark import SparkConf, SparkContext
import string
import sys

#configuration
conf = SparkConf().setMaster('local').setAppName('WordCount')
sc = SparkContext(conf=conf)

RDDtext = sc.textFile("input.txt")
palabra = sys.argv[1]

palabras = RDDtext.flatMap(lambda line: line.split())

resultado = palabras.map(lambda word: (str(word.lower()), 1))

agregado = resultado.reduceByKey(lambda a, b: a+b)
result = agregado.filter(lambda line: palabra in line)

result.saveAsTextFile("output.txt")


from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware
import uvicorn
import dataset

app = FastAPI()

# CORS Settings
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"]
)

# DB Settings
db = dataset.connect("sqlite:///hello.db")
table = db["todo"]

@app.get("/list")
def lists():
  todos = table.find(name="gamma")
  result = []
  for todo in todos:
    result.append(todo)
  print(result)
  return { "todo" : result }

@app.post("/post")
def posts(name: str, todo: str):
  table.insert({"name":name, "todo":todo})
  return { "send": { "name":name, "todo":todo } }

if __name__ == "__main__":
  uvicorn.run(app, host="127.0.0.1", port=5000)


"""
This module is to get the list of regions available in orginal subscription
"""

import re
import yaml
import modules.convert.converter as converter

# regions and the regular expression to match them
REGION_DICT = {
        "HK": [r"🇭🇰|HK|Hong|Kong|HGC|WTT|CMI|港", "🇭🇰 香港节点"],
        "TW": [r"🇹🇼|TW|Taiwan|新北|彰化|CHT|台|HINET", "🇨🇳 台湾节点"],
        "SG": [r"🇸🇬|SG|Singapore|狮城|^新[^节北]|[^刷更]新[^节北]", "🇸🇬 狮城节点"],
        "JP": [r"🇯🇵|JP|Japan|Tokyo|Osaka|Saitama|东京|大阪|埼玉|日", "🇯🇵 日本节点"],
        "KR": [r"🇰🇷|KO?R|Korea|首尔|韩|韓", "🇰🇷 韩国节点"],
        "US": [r"🇺🇸|US|America|United.*?States|美|波特兰|达拉斯|俄勒冈|凤凰城|费利蒙|硅谷|拉斯维加斯|洛杉矶|圣何塞|圣克拉拉|西雅图|芝加哥", "🇺🇸 美国节点"]
        }

# parse yaml
def parseSubs(content):
    try:
        proxies =  yaml.safe_dump(
            {"proxies": yaml.load(content, Loader=yaml.FullLoader).get("proxies")},
            allow_unicode=True,  # display characters like Chinese
            sort_keys=False  # keep the original sequence
        )
    except:
        proxies = yaml.safe_dump(
            {"proxies": converter.ConvertsV2Ray(content)},
            allow_unicode=True,  # display characters like Chinese
            sort_keys=False  # keep the original sequence
        )
    return proxies

# create a dict containg resions and corresponding proxy group
def mkList(content: list):
    result = []
    total = {}
    for u in content:
        tmp = {}
        # preprocess the content
        contentTmp = re.findall(r"- name: (.+)", u)
        contentTmp = ",".join(contentTmp)
        for i in REGION_DICT:
            if re.search(REGION_DICT[i][0], contentTmp, re.I) is not None:
                tmp[i] = REGION_DICT[i]
                total[i] = REGION_DICT[i]
        result.append(tmp)
    return result, total


import operator
from b3.clients import Client, Group
from mock import Mock, patch, ANY
from b3 import TEAM_UNKNOWN, TEAM_RED, TEAM_BLUE
from b3.clients import Alias, IpAlias
import unittest2 as unittest
from tests import B3TestCase

class Test_Client(B3TestCase):

    def setUp(self):
        B3TestCase.setUp(self)
        self.client = Client(console=self.console)

    def test_construct(self):
        c = Client(name="Courgette", guid="1234567890")
        self.assertEqual(c.name, "Courgette")
        self.assertEqual(c.exactName, "Courgette^7")
        self.assertEqual(c.guid, "1234567890")
        self.assertEqual(c.team, TEAM_UNKNOWN)
        self.assertTrue(c.connected)
        self.assertFalse(c.hide)
        self.assertEqual(c.ip, '')
        self.assertEqual(c.greeting, '')
        self.assertEqual(c.pbid, '')

    def test_team(self):
        m = Mock()
        self.client.team = m
        self.assertEqual(self.client.team, m)

    def test_team_change(self):
        # GIVEN
        self.client._team = TEAM_RED
        # THEN
        with self.assertRaiseEvent(event_type='EVT_CLIENT_TEAM_CHANGE', event_client=self.client, event_data=TEAM_BLUE):
            # WHEN
            self.client.team = TEAM_BLUE
        # GIVEN
        self.client._team = TEAM_RED
        # THEN
        with self.assertRaiseEvent(event_type='EVT_CLIENT_TEAM_CHANGE2', event_client=self.client,
                                   event_data={'previous': TEAM_RED, 'new': TEAM_BLUE}):
            # WHEN
            self.client.team = TEAM_BLUE

    def test_name_change(self):
        # GIVEN
        self.client.authed = True
        # THEN
        with self.assertRaiseEvent(event_type='EVT_CLIENT_NAME_CHANGE', event_client=self.client, event_data="cucurb"):
            # WHEN
            self.client.name = "cucurb"

    def test_makeAlias_new(self):
        self.client.id = 123
        self.console.storage.getClientAlias = Mock(side_effect = KeyError())
        self.client.makeAlias("bar")
        self.assertEquals(self.console.storage.getClientAlias.call_count, 1)
        alias = self.console.storage.getClientAlias.call_args[0][0]
        self.assertIsInstance(alias, Alias)
        self.assertEqual(alias.alias, "bar")
        self.assertEqual(alias.numUsed, 1)

    def test_makeAlias_existing(self):
        self.client.id = 123
        aliasFoo = Alias()
        aliasFoo.alias = "foo"
        aliasFoo.clientId = self.client.id
        aliasFoo.numUsed = 48
        self.console.storage.getClientAlias = Mock(side_effect = lambda x: aliasFoo)
        self.client.makeAlias("whatever")
        self.assertEquals(self.console.storage.getClientAlias.call_count, 1)
        self.assertIsInstance(aliasFoo, Alias)
        self.assertEqual(aliasFoo.alias, "foo")
        self.assertEqual(aliasFoo.numUsed, 49)

    def test_guid_readonly(self):
        self.assertFalse(self.client.authed)
        self.client.guid = "foo"
        self.assertEqual(self.client.guid, "foo")
        self.client.auth()
        self.assertTrue(self.client.authed)
        # upon guid change, prevent change and consider client not
        # authed anymore
        self.client.guid = "bar"
        self.assertFalse(self.client.authed)
        self.client.guid = "foo"

    def test_set_ip(self):
        self.client.ip = "1.2.3.4"
        self.assertEqual(self.client._ip, "1.2.3.4")
        self.client.ip = "5.6.7.8:27960"
        self.assertEqual(self.client._ip, "5.6.7.8")

    def test_makeIpAlias_new(self):
        self.client.id = 123
        self.console.storage.getClientIpAddress = Mock(side_effect = KeyError())
        self.client.makeIpAlias("1.4.7.8")
        self.assertEquals(self.console.storage.getClientIpAddress.call_count, 1)
        alias = self.console.storage.getClientIpAddress.call_args[0][0]
        self.assertIsInstance(alias, IpAlias)
        self.assertEqual(alias.ip, "1.4.7.8")
        self.assertEqual(alias.numUsed, 1)

    def test_makeIpAlias_existing(self):
        self.client.id = 123
        aliasFoo = IpAlias()
        aliasFoo.ip = "9.5.4.4"
        aliasFoo.clientId = self.client.id
        aliasFoo.numUsed = 8
        self.console.storage.getClientIpAddress = Mock(side_effect = lambda x: aliasFoo)
        self.client.makeIpAlias("whatever")
        self.assertEquals(self.console.storage.getClientIpAddress.call_count, 1)
        self.assertIsInstance(aliasFoo, IpAlias)
        self.assertEqual(aliasFoo.ip, "9.5.4.4")
        self.assertEqual(aliasFoo.numUsed, 9)

class Test_Client_groups(B3TestCase):

    def setUp(self):
        B3TestCase.setUp(self)
        self.client = Client(console=self.console)
        self.group_guest = self.console.storage.getGroup(Group(keyword="guest"))
        self.group_user = self.console.storage.getGroup(Group(keyword="user"))
        self.group_reg = self.console.storage.getGroup(Group(keyword="reg"))
        self.group_mod = self.console.storage.getGroup(Group(keyword="mod"))
        self.group_admin = self.console.storage.getGroup(Group(keyword="admin"))
        self.group_fulladmin = self.console.storage.getGroup(Group(keyword="fulladmin"))
        self.group_senioradmin = self.console.storage.getGroup(Group(keyword="senioradmin"))
        self.group_superadmin = self.console.storage.getGroup(Group(keyword="superadmin"))

    def assertGroups(self, groups):
        keywords = map(operator.attrgetter('keyword'), groups)
        self.assertListEqual(keywords, map(operator.attrgetter('keyword'), self.client.groups))
        self.assertListEqual(keywords, map(operator.attrgetter('keyword'), self.client.getGroups()))

    def test_addGroup(self):
        # GIVEN
        self.client.addGroup(self.group_mod)
        self.assertGroups([self.group_mod])
        # WHEN
        self.client.addGroup(self.group_superadmin)
        # THEN
        self.assertGroups([self.group_mod, self.group_superadmin])

    def test_rmGroup(self):
        # GIVEN
        self.client.addGroup(self.group_mod)
        self.assertGroups([self.group_mod])
        self.client.addGroup(self.group_superadmin)
        # WHEN
        self.client.remGroup(self.group_mod)
        # THEN
        self.assertGroups([self.group_superadmin])

    def test_guest_group_is_the_default_group_when_none(self):
        self.assertGroups([self.group_guest])

        self.client.remGroup(self.group_guest)
        self.assertGroups([self.group_guest])

        self.client.addGroup(self.group_admin)
        self.assertGroups([self.group_admin])

    def test_inGroup(self):
        self.assertFalse(self.client.inGroup(self.group_guest))
        self.assertFalse(self.client.inGroup(self.group_user))
        self.assertFalse(self.client.inGroup(self.group_reg))
        self.assertFalse(self.client.inGroup(self.group_mod))
        self.assertFalse(self.client.inGroup(self.group_admin))
        self.assertFalse(self.client.inGroup(self.group_fulladmin))
        self.assertFalse(self.client.inGroup(self.group_senioradmin))
        self.assertFalse(self.client.inGroup(self.group_superadmin))

        self.client.addGroup(self.group_user)
        self.assertTrue(self.client.inGroup(self.group_user))
        self.client.addGroup(self.group_reg)
        self.assertTrue(self.client.inGroup(self.group_reg))
        self.client.addGroup(self.group_mod)
        self.assertTrue(self.client.inGroup(self.group_mod))
        self.client.addGroup(self.group_admin)
        self.assertTrue(self.client.inGroup(self.group_admin))
        self.client.addGroup(self.group_fulladmin)
        self.assertTrue(self.client.inGroup(self.group_fulladmin))
        self.client.addGroup(self.group_senioradmin)
        self.assertTrue(self.client.inGroup(self.group_senioradmin))
        self.client.addGroup(self.group_superadmin)
        self.assertTrue(self.client.inGroup(self.group_superadmin))

class Test_Client_events(B3TestCase):

    def setUp(self):
        B3TestCase.setUp(self)
        self.queueEvent_patcher = patch.object(self.console, 'queueEvent')
        self.queueEvent_mock = self.queueEvent_patcher.start()

        self.admin = Client(console=self.console)
        self.client = Client(console=self.console)
        self.client.save()

    def tearDown(self):
        B3TestCase.tearDown(self)
        self.queueEvent_patcher.stop()

    def test_warn(self):
        with self.assertRaiseEvent(event_type="EVT_CLIENT_WARN", event_client=self.client, event_data={
            'reason': 'insulting admin',
            'duration': 5*60,
            'data': 'foobar',
            'admin': self.admin,
            'timeExpire': ANY
        }, event_target=None):
            self.client.warn(duration='5h', warning='insulting admin', keyword=None, admin=self.admin, data='foobar')

    def test_notice(self):
        with self.assertRaiseEvent(event_type="EVT_CLIENT_NOTICE", event_client=self.client, event_data={
            'notice': "keep a eye on this guy",
            'admin': self.admin,
            'timeAdd': ANY
        }):
            self.client.notice(notice="keep a eye on this guy", spare=None, admin=self.admin)

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


# Deep Q-learning (reinforcement learning)
import pygame
import random

# framerate
fps = 60

# Size of window
window_height = 400
window_width = 400

# Size of paddle
paddle_width = 10
paddle_height = 60

# Size of ball
ball_width = 10
ball_height = 10

# Speed
paddle_speed = 2
ball_x_speed = 3
ball_y_speed = 2

# Colors
white = (255, 255, 255)
black = (0, 0, 0)

# Initialize
screen = pygame.display.set_mode(window_width, window_height)

def draw_ball(ball_x_pos, ball_y_pos):
	ball = pygame.rect(ball_x_pos, ball_y_pos, ball_width, ball_height)
	pygame.draw.rect(screen, white, ball)

def draw_paddle1(paddle1_y_pos):
	paddle1 = pygame.rect(paddle_buffer, paddle1_y_pos, paddle_width, paddle_height)
	pygame.draw.rect(screen, white, paddle1)

def draw_paddle2(paddle2_y_pos):
	paddle2 = pygame.rect(window_width - paddle_buffer - paddle_width, paddle2_y_pos, paddle_width, paddle_height)
	pygame.draw.rect(screen, white, paddle2)

def update_ball(paddle1_y_pos, paddle2_y_pos, ball_x_pos, ball_y_pos, ball_x_direction, ball_y_direction):
	# Update x and y positions
	ball_x_pos = ball_x_pos + ball_x_direction * ball_x_speed
	ball_y_pos = ball_y_pos + ball_y_direction * ball_y_speed
	score = 0

	# Check for collision
	if (ball_x_pos <= paddle_buffer + paddle_width and ball_y_pos + ball_height >= paddle1_y_pos and ball_y_pos - ball_height <= paddle1_y_pos + paddle_height):
		ball_x_direction = 1
	elif (ball_x_pos <= 0):
		ball_x_direction = 1 # -1 ?
		score = -1
		return [score, paddle1_y_pos, paddle2_y_pos, ball_x_pos, ball_y_pos, ball_x_direction, ball_y_direction]
	if (ball_x_pos >= window_width - paddle_width - paddle_buffer and ball_y_pos + ball_height >= paddle2_y_pos and ball_y_pos - ball_height <= paddle2_y_pos + paddle_height):
		ball_x_direction = -1
	elif(ball_x_pos >= window_width - ball_width):
		ball_x_direction = -1
		score = 1
		return [score, paddle1_y_pos, paddle2_y_pos, ball_x_pos, ball_y_pos, ball_x_direction, ball_y_direction]
	if(ball_y_pos <= 0):
		ball_y_pos = 0
		ball_y_direction = 1
	elif(ball_y_pos >= window_height - ball_height):
		ball_y_pos = window_height - ball_height
		ball_y_direction = -1
		return [score, paddle1_y_pos, paddle2_y_pos, ball_x_pos, ball_y_pos, ball_x_direction, ball_y_direction]

def update_paddle1(action, paddle1_y_pos):
	# if move up
	if(action[1] == 1):
		paddle1_y_pos = paddle1_y_pos - paddle_speed
	# if move down
	if(action[2] == 1):
		paddle1_y_pos = paddle1_y_pos + paddle_speed
	# dont let it move off the screen
	if(paddle1_y_pos < 0):
		paddle1_y_pos = 0
	if(paddle1_y_pos > window_height - paddle_height):
		paddle1_y_pos = window_height - paddle_height
	return paddle1_y_pos

def update_paddle2(action, ball_y_pos):
	# if move up
	if(action[1] == 1):
		paddle2_y_pos = paddle2_y_pos - paddle_speed
	# if move down
	if(action[2] == 1):
		paddle1_y_pos = paddle1_y_pos + paddle_speed
	# dont let it move off the screen
	if(paddle1_y_pos < 0):
		paddle1_y_pos = 0
	if(paddle1_y_pos > window_height - paddle_height):
		paddle1_y_pos = window_height - paddle_height
	return paddle1_y_pos

class Pong:
	def __init__(self):
		# random number for initial direction of ball
		num = random.randInt(0, 9)
		# keep score
		self.tally = 0
		# Initialize positions of our paddle
		self.paddle1_y_pos = window_height / 2 - paddle_height / 2
		self.paddle2_y_pos = window_height / 2 - paddle_height / 2
		# Ball direction definition
		self.ball_x_direction = 1
		self.ball_y_direction = 1
		# Starting point
		self.ball_x_pos = window_height / 2 - ball_width / 2

	def get_present_frame(self):
		pygame.event.pump()
		# make background black
		screen.fill(black)
		draw_paddle1(self.paddle1_y_pos)
		draw_paddle2(self.paddle2_y_pos)
		draw_ball(self.ball_x_pos, self.ball_y_pos)
		# get pixels
		image_data = pygame.surfarray.array3d(pygame.display.get_surface())
		# update the window
		pygame.display.flip()
		# return screen data
		return image_data

	def get_next_frame(self, action):
		pygame.event.pump()
		screen.fill(black)
		self.paddle1_y_pos = update_paddle1(action, self.paddle1_y_pos)
		draw_paddle1(self.paddle1_y_pos)
		self.paddle2_y_pos = update_paddle2(self.paddle2_y_pos, self.ball_y_pos)
		draw_ball(self.ball_x_pos, self.ball_y_pos)
		image_data = pygame.surfarray.array3d(pygame.display.get_surface())
		pygame.display.flip()
		self.tally = self.tally + score
		return [score, image_data]


import argparse
import cv2
import gym
import copy
import os
import box_constants
import atari_constants
import numpy as np
import tensorflow as tf

from rlsaber.log import TfBoardLogger, JsonLogger, dump_constants
from rlsaber.explorer import LinearDecayExplorer, ConstantExplorer
from rlsaber.replay_buffer import ReplayBuffer
from rlsaber.trainer import Trainer, Evaluator, Recorder
from rlsaber.env import EnvWrapper
from actions import get_action_space
from network import make_cnn
from agent import Agent
from datetime import datetime

def main():
    date = datetime.now().strftime("%Y%m%d%H%M%S")
    parser = argparse.ArgumentParser()
    parser.add_argument('--env', type=str, default='PongDeterministic-v4')
    parser.add_argument('--outdir', type=str, default=date)
    parser.add_argument('--logdir', type=str, default=date)
    parser.add_argument('--load', type=str, default=None)
    parser.add_argument('--render', action='store_true')
    parser.add_argument('--demo', action='store_true')
    parser.add_argument('--record', action='store_true')
    args = parser.parse_args()

    outdir = os.path.join(os.path.dirname(__file__), 'results/' + args.outdir)
    if not os.path.exists(outdir):
        os.makedirs(outdir)
    logdir = os.path.join(os.path.dirname(__file__), 'logs/' + args.logdir)

    env = gym.make(args.env)

    # box environment
    if len(env.observation_space.shape) == 1:
        constants = box_constants
        actions = range(env.action_space.n)
        state_shape = [env.observation_space.shape[0], constants.STATE_WINDOW]
        state_preprocess = lambda state: state
        # (window_size, dim) -> (dim, window_size)
        phi = lambda state: np.transpose(state, [1, 0])
    # atari environment
    else:
        constants = atari_constants
        actions = get_action_space(args.env)
        state_shape = [84, 84, constants.STATE_WINDOW]
        def state_preprocess(state):
            state = cv2.cvtColor(state, cv2.COLOR_RGB2GRAY)
            state = cv2.resize(state, (210, 160))
            state = cv2.resize(state, (84, 110))
            state = state[18:102, :]
            return np.array(state, dtype=np.float32) / 255.0
        # (window_size, H, W) -> (H, W, window_size)
        phi = lambda state: np.transpose(state, [1, 2, 0])

    # save constant variables
    dump_constants(constants, os.path.join(outdir, 'constants.json'))

    # exploration
    if constants.EXPLORATION_TYPE == 'linear':
        duration = constants.EXPLORATION_DURATION
        explorer = LinearDecayExplorer(final_exploration_step=duration)
    else:
        explorer = ConstantExplorer(constants.EXPLORATION_EPSILON)

    # optimizer
    if constants.OPTIMIZER == 'adam':
        optimizer = tf.train.AdamOptimizer(constants.LR)
    else:
        optimizer = tf.train.RMSPropOptimizer(
            learning_rate=constants.LR, momentum=constants.MOMENTUM,
            epsilon=constants.EPSILON)

    # wrap gym environment
    env = EnvWrapper(
        env,
        s_preprocess=state_preprocess,
        r_preprocess=lambda r: np.clip(r, -1, 1)
    )

    replay_buffer = ReplayBuffer(constants.REPLAY_BUFFER_SIZE)

    sess = tf.Session()
    sess.__enter__()

    model = make_cnn(convs=constants.CONVS, hiddens=constants.FCS)

    agent = Agent(
        model,
        actions,
        state_shape,
        replay_buffer,
        explorer,
        optimizer,
        gamma=constants.GAMMA,
        grad_norm_clipping=constants.GRAD_CLIPPING,
        phi=phi,
        learning_starts=constants.LEARNING_START_STEP,
        batch_size=constants.BATCH_SIZE,
        train_freq=constants.UPDATE_INTERVAL,
        target_network_update_freq=constants.TARGET_UPDATE_INTERVAL
    )

    sess.run(tf.global_variables_initializer())

    saver = tf.train.Saver()
    if args.load is not None:
        saver.restore(sess, args.load)

    train_writer = tf.summary.FileWriter(logdir, sess.graph)
    tflogger = TfBoardLogger(train_writer)
    tflogger.register('reward', dtype=tf.float32)
    tflogger.register('eval_reward', dtype=tf.float32)
    jsonlogger = JsonLogger(os.path.join(outdir, 'reward.json'))

    # callback on the end of episode
    def end_episode(reward, step, episode):
        tflogger.plot('reward', reward, step)
        jsonlogger.plot(reward=reward, step=step, episode=episode)

    def after_action(state, reward, global_step, local_step):
        if global_step > 0 and global_step % constants.MODEL_SAVE_INTERVAL == 0:
            path = os.path.join(outdir, 'model.ckpt')
            saver.save(sess, path, global_step=global_step)

    evaluator = Evaluator(
        env=copy.deepcopy(env),
        state_shape=state_shape[:-1],
        state_window=constants.STATE_WINDOW,
        eval_episodes=constants.EVAL_EPISODES,
        recorder=Recorder(outdir) if args.record else None,
        record_episodes=constants.RECORD_EPISODES
    )
    should_eval = lambda step, episode: step > 0 and step % constants.EVAL_INTERVAL == 0
    end_eval = lambda s, e, r: tflogger.plot('eval_reward', np.mean(r), s)

    trainer = Trainer(
        env=env,
        agent=agent,
        render=args.render,
        state_shape=state_shape[:-1],
        state_window=constants.STATE_WINDOW,
        final_step=constants.FINAL_STEP,
        after_action=after_action,
        end_episode=end_episode,
        training=not args.demo,
        evaluator=evaluator,
        should_eval=should_eval,
        end_eval=end_eval
    )
    trainer.start()

if __name__ == '__main__':
    main()


import tensorflow as tf
import numpy as np
from random import *
import random
import matplotlib.pyplot as plt

# Resizes all number images from 28x28 to 14x14
# Rounds each pixel above 128 to 2, and below 128 to -2
# Resizes all number images from 28x28 to 14x14
# Rounds each pixel above 128 to 1.0 and below to 0.0
def resize_number_image(number):
    new_number = np.zeros((14, 14))
    for i in range(14):
        for j in range(14):
            avg_val = (int(number[i*2, j*2]) + int(number[i*2 + 1, j*2]) + int(number[i*2, j*2 + 1]) + int(number[i*2 + 1, j*2 + 1])) / 4
            new_number[i, j] = 2 if avg_val > 60 else -2  # avg_val / 255

    return new_number

# Retrieves the Mnist dataset, rescales it and saves it as .npy file
def create_mnist_array(filename):
    (x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
    numbers_array = []
    for num in range(0, 10):
        print(num)
        num_arr = []
        for number, label in zip(x_train, y_train):
            if label == num:
                num_arr.append(np.asarray(resize_number_image(number).flatten()))
        numbers_array.append(np.asarray(num_arr))

    num_arr = np.asarray(numbers_array)

    np.save(filename, num_arr, allow_pickle=True)

# retrieves the array with the given name
def load_mnist_data(filename):
    return np.load(filename, allow_pickle=True)

# Hides part of a number image (given percentage)
def hide_img_partial(number_img, portion, img_shape=(14, 14)):
    min_row = int((1.0 - portion) * img_shape[0])
    for i in range(min_row, img_shape[0]):
        for j in range(img_shape[1]):
            number_img[i * img_shape[0] + j] = 2

# Flips random bits of the image with a given percentage (gaussian)
def add_img_noise(number_img, perc):
    for idx in range(len(number_img)):
        r_num = random.uniform(0, 1)
        number_img[idx] = 0 - number_img[idx] if r_num < perc else number_img[idx]

# returns a given amount of images per given label
def get_random_images(amnt, num_arr, labels=None):
    if labels is None:
        labels = list(range(10))

    images_arr = []
    labels_arr = []
    for label in labels:
        for _ in range(amnt):
            rand_idx = randint(0, len(num_arr[label])-1)
            images_arr.append(num_arr[label][rand_idx])
            labels_arr.append(label)

    return np.asarray(images_arr)

# Replaces 2 with 1.0 and -2 with 0.0 (useful for training a classifier)
def image_to_floats(number_img):
    return float(number_img > 0)

# converges to an image iteratively
def converge(pattern, weights, max_it=50):
    pattern = (np.sign(pattern) + 1) / 2
    dim_size = len(pattern)
    max_val = np.max(weights)
    weights -= max_val/2

    for _ in range(max_it):
        old_pat = pattern.copy()
        bits = list(range(dim_size))
        shuffle(bits)

        for b in bits:
            act = np.sum(weights[b] * pattern)
            if act > 0:
                pattern[b] = 1.0
            else:
                pattern[b] = 0.0

        if np.all(pattern == old_pat):
            return pattern

def convert_mOja_img(pattern):
    img = np.zeros((14, 14))
    for i in range(0, 14):
        for j in range(0, 14):
            if pattern[i * 14 + j] > 0:
                img[i, j] = 1.0
            else:
                img[i, j] = 0.0

    return img

# Plot multiple digit images
def show_digit_images(patterns, title, annotations=""):
    # Determine amount of rows and columns (row amnt. = col amnt.)
    pat_amnt = len(patterns)
    fig = plt.figure(figsize=(14, 14))
    fig.suptitle(title, fontsize=30)
    columns = int(np.sqrt(pat_amnt) + 0.5)
    rows = columns

    # Add every pattern as an image to the figure
    for i in range(1, pat_amnt+1):
        img = convert_mOja_img(patterns[i-1])
        fig.add_subplot(rows, columns, i)
        # Add the FFN prediction of the image as a green digit in the top corner
        if annotations != "":
            plt.text(0, 3, str(annotations[i-1]), color="lime", fontsize=30, fontstyle="oblique")
        plt.imshow(img, cmap=plt.get_cmap("gray"))
        #fig.set_size_inches(2, 2)
        #plt.savefig('digits1.png', dpi=1200)
        plt.axis('off')


import json
import random

import cv2
import keras
import matplotlib.image
import numpy as np

import app_params
from app_params import SINGLE_CATEGORIES, SINGLE_CATEGORY

IMAGE_SIZE = 256  # Size of the input images
NORMALIZE = True  # Normalize RGB values
BATCH_SIZE = 32
EPOCHS = 5
EARLY_STOP = True
LEARNING_RATE = 0.1
CONV_LAYERS = 4  # Number of Convolution+Pooling layers
CONV_NUM_FILTERS = 32
CONV_FILTER_SIZE = (5, 5)
CONV_POOLING_SIZE = (3, 3)
CONV_STRIDE = 1

class TrainParams:
    def __init__(
            self,
            nn_id=0,
            batch_size=BATCH_SIZE,
            epochs=EPOCHS,
            learning_rate=LEARNING_RATE,
            early_stop=EARLY_STOP,
            image_size=IMAGE_SIZE,

            conv_layers=CONV_LAYERS,
            conv_num_filters=CONV_NUM_FILTERS,
            conv_filter_size=CONV_FILTER_SIZE,
            conv_pooling_size=CONV_POOLING_SIZE,
            conv_stride=CONV_STRIDE,

            base_dir="./out/"
    ):
        self.nn_id = nn_id
        self.batch_size = batch_size
        self.epochs = epochs
        self.learning_rate = learning_rate
        self.early_stop = early_stop
        self.image_size = image_size

        self.conv_layers = conv_layers
        self.conv_num_filters = conv_num_filters
        self.conv_filter_size = conv_filter_size
        self.conv_pooling_size = conv_pooling_size
        self.conv_stride = conv_stride

        self.base_dir = base_dir

    def __str__(self):
        return json.dumps(self, default=lambda o: o.__dict__,
                          sort_keys=True, indent=4)

class CocoBatchGenerator(keras.utils.Sequence):
    def __init__(self, imgids, coco_path, params, imgids_to_cats):
        self.img_order = imgids
        self.coco_path = coco_path
        self.params = params
        self.imgids_to_cats = imgids_to_cats

    def __len__(self):
        return int(np.floor(len(self.img_order) / self.params.batch_size))

    def __getitem__(self, index):
        # Generate indexes of the batch
        indexes = self.img_order[index * self.params.batch_size: (index + 1) * self.params.batch_size]

        # Generate data
        x, y = self.__data_generation(indexes)
        return x, y

    def on_epoch_end(self):
        random.shuffle(self.img_order)

    def __data_generation(self, imgids):
        # Load image files
        input_imgs = [matplotlib.image.imread(
            self.coco_path + '/images/' + app_params.dataType + '/' + ('0' * (12 - len(str(imgid)))) + str(
                imgid) + '.jpg'
        ) for imgid in imgids]

        # Rescale all images to the same size
        input_imgs = [preprocess_image(img, self.params.image_size, NORMALIZE) for img in input_imgs]

        # Convert the batch's X and Y to be fed to the net
        x_train = np.asarray(input_imgs)
        if not SINGLE_CATEGORIES:
            y_train = np.array([self.imgids_to_cats[imgid] for imgid in imgids])
        else:
            y_train = np.array([[self.imgids_to_cats[imgid][SINGLE_CATEGORY]] for imgid in imgids])
        return x_train, y_train

class KFoldCrossValidator:
    def __init__(self, k, data):
        self.k = k
        self.data = data

    def __len__(self):
        return self.k

    def __getitem__(self, item):
        val_size = len(self.data) // self.k
        train_data = self.data[:item * val_size] + self.data[(item + 1) * val_size:]
        val_data = self.data[item * val_size: (item + 1) * val_size]
        return train_data, val_data

def preprocess_image(img, image_size, normalize):
    """
    Returns the result of image preprocessing on img
    """
    # Rescale image to a fixed size
    img = cv2.resize(img, (image_size, image_size))

    # If grayscale, convert to RGB
    if img.shape == (image_size, image_size):
        img = np.repeat(img, 3).reshape(image_size, image_size, 3)

    # If enabled, normalize pixel values (ranges from [0 - 255] to [-1.0 - 1.0])
    if normalize:
        img = ((img / 255.0) - .5) * 2

    return img

def set_random_params(p):
    def make_random_params():
        param_values = {
            'learning_rate': [0.001, 0.01, 0.1, 1.0],
            'conv_layers': [1, 2, 4, 8],
            'conv_num_filters': [16, 32, 64],
            'conv_filter_size': [2, 3, 4, 6, 10],
            'conv_stride': [1, 2, 3, 4, 5],
            'conv_pooling_size': [2, 3, 5, 10]
        }
        res = {}
        for k, v in param_values.items():
            res[k] = random.choice(v)
        return res

    for k, v in make_random_params().items():
        setattr(p, k, v)


import sys
import torch
import torch.nn.functional as F
from torch import nn

sys.path.append(r"../utils")
from utils import initialize_weights

class ConvBNReLU(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride, padding, dilation,
                 use_relu=True):
        super(ConvBNReLU, self).__init__()
        self.conv = nn.Conv3d(
                in_channels, out_channels, kernel_size=kernel_size, stride=stride,
                padding=padding, dilation=dilation, bias=False)
        self.bn = nn.BatchNorm3d(out_channels)
        if use_relu:
            self.relu = nn.ReLU(inplace=True)
        else:
            self.relu = None

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        if self.relu is not None:
            x = self.relu(x)
        return x

class CARAFE(nn.Module):
    def __init__(self, in_channels, mid_channels=64, scale=2, k_up=5, k_enc=3):
        super(CARAFE, self).__init__()
        self.scale = scale
        self.comp = ConvBNReLU(in_channels, mid_channels, kernel_size=1, stride=1,
                               padding=0, dilation=1)
        self.enc = ConvBNReLU(mid_channels, (scale * k_up) ** 3, kernel_size=k_enc,
                              stride=1, padding=k_enc // 2, dilation=1,
                              use_relu=False)
        self.pix_shf = nn.PixelShuffle(scale)

        self.upsmp = nn.Upsample(scale_factor=scale, mode='nearest')
        self.unfold = nn.Unfold(kernel_size=k_up, dilation=scale,
                                padding=k_up // 2 * scale)

    def forward(self, X):
        b, c, h, w, d = X.size()
        h_, w_ , d_ = h * self.scale, w * self.scale, d * self.scale

        W = self.comp(X)  # b * m * h * w * d
        W = self.enc(W)  # b * 100 * h * w * d
        W = self.pix_shf(W)  # b * 25 * h_ * w_ * d_
        W = F.softmax(W, dim=1)  # b * 25 * h_ * w_ * d_

        X = self.upsmp(X)  # b * c * h_ * w_ * d_
        X = self.unfold(X)  # b * 125c * h_ * w_ * d_
        X = X.view(b, c, -1, h_, w_, d_)  # b * 25 * c * h_ * w_ * d_

        X = torch.einsum('bkhwd,bckhwd->bchwd', W, X)  # b * c * h_ * w_ * d_
        return X

class BasicBlock(nn.Module):
    expansion = 1

    def __init__(self, in_channels, out_channels, stride=(1, 1, 1), downsample=None):
        super(BasicBlock, self).__init__()
        self.conv1 = nn.Conv3d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)
        self.BN1 = nn.BatchNorm3d(out_channels)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = nn.Conv3d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)
        self.BN2 = nn.BatchNorm3d(out_channels)
        self.stride = stride
        self.downsample = downsample

    def forward(self, x):
        residual = x
        out = self.conv1(x)
        out = self.BN1(out)
        out = self.relu(out)
        out = self.conv2(out)
        out = self.BN2(out)
        if self.downsample is not None:
            residual = self.downsample(x)
        out += residual
        out = self.relu(out)
        return out

class _EncoderBlock3D(nn.Module):
    def __init__(self, in_channels, out_channels, pool_kernal=2, dropout=False):
        super(_EncoderBlock3D, self).__init__()
        if out_channels == 32:
            layers = [
                BasicBlock(in_channels, out_channels)
            ]
        else:
            downsample = nn.Sequential(
                nn.Conv3d(in_channels, out_channels * BasicBlock.expansion, kernel_size=1, stride=pool_kernal),
                nn.BatchNorm3d(out_channels * BasicBlock.expansion)
            )
            layers = [
                BasicBlock(in_channels, out_channels, stride=pool_kernal, downsample=downsample),
            ]

        if dropout:
            layers.append(nn.Dropout(p=0.5))
        self.encode = nn.Sequential(*layers)

    def forward(self, x):
        return self.encode(x)

class _DecoderBlock3D(nn.Module):
    def __init__(self, in_channels, middle_channels, out_channels):
        super(_DecoderBlock3D, self).__init__()
        self.decode = nn.Sequential(
            nn.Conv3d(in_channels, middle_channels, kernel_size=3, padding=1, bias=False),
            nn.BatchNorm3d(middle_channels),
            nn.ReLU(inplace=True),
            nn.Conv3d(middle_channels, middle_channels, kernel_size=3, padding=1, bias=False),
            nn.BatchNorm3d(middle_channels),
            nn.ReLU(inplace=True),
            nn.ConvTranspose3d(middle_channels, out_channels, kernel_size=2, stride=2, bias=False),
        )

    def forward(self, x):
        return self.decode(x)

class U_net3D_Resnet(nn.Module):
    def __init__(self, num_classes, dropout=True, initial=True):
        super(U_net3D_Resnet, self).__init__()
        self.conv3D = nn.Conv3d(1, 32, kernel_size=3, padding=1, bias=False)
        self.enc1 = _EncoderBlock3D(32, 32)
        self.enc2 = _EncoderBlock3D(32, 64)
        self.enc3 = _EncoderBlock3D(64, 128, dropout=dropout)
        self.center = _DecoderBlock3D(128, 256, 128)
        self.dec3 = _DecoderBlock3D(256, 128, 64)
        self.dec2 = _DecoderBlock3D(128, 64, 32)
        self.dec1 = nn.Sequential(
            nn.Conv3d(64, 32, kernel_size=3, padding=1, bias=False),
            nn.BatchNorm3d(32),
            nn.ReLU(inplace=True),
            nn.Conv3d(32, 32, kernel_size=3, padding=1, bias=False),
            nn.BatchNorm3d(32),
            nn.ReLU(inplace=True),
        )
        self.final = nn.Conv3d(32, num_classes, kernel_size=1, bias=False)
        self.sigmoid = nn.Sigmoid
        self.softmax = nn.Softmax(dim=1)
        if initial:
            initialize_weights(self)

    def forward(self, x):
        con1 = self.conv3D(x)
        enc1 = self.enc1(con1)
        enc2 = self.enc2(enc1)
        enc3 = self.enc3(enc2)

        center = self.center(enc3)
        dec3 = self.dec3(torch.cat([F.interpolate(center, enc3.size()[2:], mode='trilinear', align_corners=False), enc3], 1))
        dec2 = self.dec2(torch.cat([F.interpolate(dec3, enc2.size()[2:], mode='trilinear', align_corners=False), enc2], 1))
        dec1 = self.dec1(torch.cat([F.interpolate(dec2, enc1.size()[2:], mode='trilinear', align_corners=False), enc1], 1))
        final = self.final(dec1)
        return F.interpolate(final, x.size()[2:], mode='trilinear', align_corners=False)