import matplotlib.pyplot as plt
import random
import numpy as np

def gradient_regression(X,y,alpha,b,w):
    dw = 0.0
    db = 0.0
    # we make the model by using all the samples
    for i in range(len(X)):
        aux = -2.0*(y[i] - (w*X[i] + b))
        db = db + aux # this solver can easily overflow
        dw = dw + X[i]*aux # this solver can easily overflow
    aux = 1.0/float(len(X))
    b = b - aux*db*alpha
    w = w - aux*dw*alpha
    return b, w

def gradient_regression2(X,y,alpha,b,w):
    aux = -2*(y-(w*X+b)).sum()
    b = b - alpha*aux/float(len(X))
    w = w - alpha*aux/float(len(X))
    return b,w

def plot(fig,X,y,b,w,epochs):
    axs[fig].plot(X,y,"yo", label= "Samples")
    X = np.array(X)
    axs[fig].plot(X,w*X+b, "k-",label="Regression loss: " + "{:9.2f}".format(loss(X,y,b,w)))
    axs[fig].set_xlabel("{:5.0f}".format(epochs) + "epochs")
    axs[fig].legend()
    axs[fig].grid()
    return

def model(X,y,alpha,b,w,epochs):
    fig = 0
    for e in range(epochs):
        b,w = gradient_regression(X,y,alpha,b,w)
        if e % 3000 == 0:
            plot(fig,X,y,b,w,e)
            fig += 1
    return b,w

def prediction(x,b,w):
    return x*w+b

def loss(X,y,b,w):
    sum = 0
    for i in range(len(X)):
        sum += (y[i]-prediction(X[i],b,w)) ** 2
    return sum/len(X)

def create_samples(n):
    y = []
    X = list(range(40))
    for i in range(len(X)):
        y.append(20+X[i]+random.random()*20)
    return X,y

def create_samples2(n):
    X = np.array(list(range(40)))
    y = 20+X+np.random.rand(40)*20
    return X,y

X,y = create_samples2(40)

# in this example, we dont change epoch's value, since we just show
# plots for the values (0,3000,6000,9000)

EPOCHS = 9001

# Linear regression evolution
fig, axs = plt.subplots(1,4,figsize=(15,4))
# b and w parameters can be better initialized
b,w = model(X,y,0.001, random.random(), random.random(), EPOCHS)
y = []
for i in range(len(X)):
    y.append((X[i]-10)**2 + random.random()*20*abs(len(X)/2-i))
# loss evolution
fig, axs = plt.subplots(1,4,figsize=(15,4))
# b and w parameters can be better initialized
model(X,y,0.001,random.random(), random.random(), EPOCHS)

plt.show()

print(prediction(10,b,w))
print(prediction(20,b,w))


import tkinter as tk
import requests

class WeatherApp:
    def __init__(self):
        self.api_key = "YOUR_API_KEY"
        self.root = tk.Tk()
        self.root.title("Weather App")

        self.city_label = tk.Label(self.root, text="City:")
        self.city_label.grid(row=0, column=0)

        self.city_entry = tk.Entry(self.root, width=30)
        self.city_entry.grid(row=0, column=1)

        self.submit_button = tk.Button(self.root, text="Get Weather", command=self.get_weather)
        self.submit_button.grid(row=0, column=2)

        self.weather_label = tk.Label(self.root, text="")
        self.weather_label.grid(row=1, column=0, columnspan=3)

    def get_weather(self):
        city = self.city_entry.get()
        url = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={self.api_key}&units=metric"
        response = requests.get(url)
        data = response.json()
        try:
            temperature = data["main"]["temp"]
            description = data["weather"][0]["description"].capitalize()
            message = f"The temperature in {city} is {temperature:.1f}°C and the weather is {description}."
        except KeyError:
            message = f"Could not find weather information for {city}."
        self.weather_label.config(text=message)

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

if __name__ == "__main__":
    app = WeatherApp()
    app.run()


import numpy as np
import dataset.util as utl

x, t = utl.get_data()
network = utl.init_network()

W1, W2, W3 = network['W1'], network['W2'], network['W3']

print(x.shape)
print(x[0].shape)
print(W1.shape)
print(W2.shape)
print(W3.shape)

batch_size = 100
accuracy_cnt = 0
for i in range(0, len(x), batch_size):
    x_batch = x[i:i+batch_size]
    y_batch = utl.predict(network, x_batch)
    p = np.argmax(y_batch, axis=1)
    accuracy_cnt += np.sum(p == t[i:i+x_batch])

x = np.array([[0.1, 0.8, 0.1], [0.3, 0.1, 0.6], [0.2, 0.5, 0.3], [0.8, 0.1, 0.1]])
y = np.argmax(x, axis=1)
print(y)

y = np.array([1, 2, 1, 0])
t = np.array([1, 2, 0, 0])
print(y == t)
print(np.sum(y==t))


#!/usr/bin/python

import cv2
import numpy as np

# Constants

cam = cv2.VideoCapture(0)

X1=260
X2=300
Y1=200
Y2=400

B=0
G=0
R=0
sum=0

while True:

        ret, img = cam.read()

        if img.any():

                for i in range(X1,X2):
                        for j in range(Y1,Y2):
                                B = B + img[i][j][0]
                                G = G + img[i][j][1]
                                R = R + img[i][j][2]
                                sum = sum + 1
                break

avB=B/sum
avG=G/sum
avR=R/sum

if (avR > 200):
        if (avG > 200):
                print('YELLOW')
        if (avG < 100) and (avB < 100):
                print('RED')

elif (avR < 100):
        if (avB < 80):
                print('GREEN')
        if (avG < 80):
                print('BLUE')
        if (avG > 180) and (avB > 180):
                print('CYAN')

elif (avG < 80) and (avR > 80):
        print('PURPLE')

elif (avG > 80) and (avR > 80) and (avB > 80):
        print('GREY')

else:
        print('No color found')

print('R')
print(avR)
print('G')
print(avG)
print('B')
print(avB)

cv2.imwrite("ColorCalib.png", img)

cam.release()


#!/usr/bin/env python
# coding:utf-8
"""
Name : WangyiUtilOnFlyai.py
Author  : 莫须有的嚣张
Contect : 291255700
Time    : 2019/7/28 上午9:42
Desc:
"""
from time import clock

import matplotlib.pyplot as plt
import pandas as pd
from PIL import Image
from flyai.source.base import DATA_PATH

from data_helper import *
from hyperparameter import random_per_epoch, reduce_lr_per_epochs, num_classes, train_vs_val
from path import DATA_PATH

DATA_ID = 'MedicalClass'

# 保留的图片中心的比例，如80%，写0.8，同时在prediction.py里要做修改
center_scale = 0.85

def get_1_x_data(image_path):
    img = Image.open(os.path.join(DATA_PATH, DATA_ID, image_path))

    return img

def get_1_y_data(label):

    return label

'''

lr_level = [
    3e-4,
    0.0001,
    # 3e-5,
    # 1e-5,
]

optimizer_level = [
    'sgd',
    'rmsprop',
    'adagrad',
    # 'adadelta',
    'adam',
    # 'adamax'
]

optimizer_name = {
    'sgd': optmzs.SGD,
    'rmsprop': optmzs.RMSprop,
    'adagrad': optmzs.Adagrad,
    # 'adadelta': optmzs.Adadelta,
    'adam': optmzs.Adam,
    # 'adamax': optmzs.Adamax
}

class OptimizerByWangyi():
    def __init__(self):
        self.optimizer_iterator = 0
        self.lr_iterator = 0
        self.pationce_count = 0
        self.lr_level = 0  # 在训练时判断后+1 使用
        self.now_optimizer = None
        self.now_opt_name = None  # 当前的优化器
        self.now_opt_lr = None  # 当前的学习率
        self.now_opt_name_lv = -1  # 当前的优化器索引
        self.now_opt_lr_lv = -1  # 当前的学习率索引

    def get_create_optimizer(self, name, lr_num):
        if name is None or lr_num <= 0:
            raise ValueError('请指定正确的优化器/学习率')

        self.now_optimizer = optimizer_name[name]
        self.now_opt_name = name
        self.now_opt_lr = lr_num
        self.now_opt_name_lv = optimizer_level.index(name)
        self.now_opt_lr_lv = lr_level.index(lr_num)
        print('采用了优化器：', name, '--学习率:', lr_num)
        return self.now_optimizer, lr_num

    def get_next(self, optimzer=None, lr=None):

        if optimzer is not None:
            name_1 = optimzer
        else:
            name_1 = optimizer_level[self.optimizer_iterator]

        if lr is not None:
            lr_1 = lr
        else:
            lr_1 = lr_level[self.lr_iterator]

        x = self.get_create_optimizer(name_1, lr_1)

        self.lr_iterator = (self.lr_iterator + 1) % len(lr_level)
        if self.lr_iterator == 0:
            self.optimizer_iterator = (self.optimizer_iterator + 1) % len(optimizer_level)
        return x

    def get_random_opt(self):
        name = np.random.randint(0, len(optimizer_name))
        lr = np.random.randint(0, len(lr_level))
        print('启动随机de学习率')
        # self.now_opt_name = name
        # self.now_opt_lr = lr
        return self.get_create_optimizer(optimizer_level[name], lr_level[lr])

    def reduce_lr_by_loss_and_epoch(self, get_loss, get_epoch):
        tmp_opt = None

        # 多少个epochs后启动随机学习率，对应Warmup Scheduler的实现
        if get_epoch % random_per_epoch == random_per_epoch - 1:
            print('经过%d epochs：' % random_per_epoch)
            tmp_opt = self.get_random_opt()

        # 每此学习率都能规律下降，例如1e-3 到 1e-4 到1e-5

        if get_epoch < random_per_epoch:
            pass
        elif (get_epoch % random_per_epoch) % reduce_lr_per_epochs == reduce_lr_per_epochs - 1:
            # 降低学习率
            self.now_opt_lr_lv = (self.now_opt_lr_lv + 1) % len(lr_level)  # lr_level的范围
            print('经过%d epochs降低学习率' % reduce_lr_per_epochs)
            tmp_opt = self.get_create_optimizer(self.now_opt_name, lr_level[self.now_opt_lr_lv])

        # 调整学习率，且只执行一次
        if get_loss < 0.4 and self.lr_level < 1:
            print('train loss 低于 %.1f' % 0.4)
            tmp_opt = self.get_create_optimizer(name='adagrad', lr_num=1e-4)
            self.lr_level = 1

        elif get_loss < 0.1 and self.lr_level < 2:
            print('train loss 低于 %.1f' % 0.1)
            tmp_opt = self.get_create_optimizer(name='sgd', lr_num=3e-4)
            self.lr_level = 2

        return tmp_opt
'''

class dynamicBatchSize():
    def __init__(self, num_class):
        self.n = num_class
        self.now_batch = [1] * num_class

    def getSizebyAcc(self, acc, wrong_acc=None):
        normal_batch = [
            7 ,  # 0
            160 	,  # 1
            173 	,  # 2
            117 	,  # 3
            142 	,  # 4
            3 	,  # 5
            87 	,  # 6
            86 	,  # 7
            62 	,  # 8
            10 	,  # 9
            135 	,  # 10
            6 	,  # 11
            747 	,  # 12
            133 	,  # 13
            293 	,  # 14
            11 	,  # 15
            36 	,  # 16
            84 	,  # 17
            40 	,  # 18
            1 	,  # 19
            128 	,  # 20
            133 	,  # 21
            86 	,  # 22
            115 	,  # 23
            17 	,  # 24
            114 	,  # 25
            5 	,  # 26
            22 	,  # 27
            4 	,  # 28
            149 	,  # 29
            200 	,  # 30
            109 	,  # 31
            79 	,  # 32
            4 	,  # 33
            6 	,  # 34
            2 	,  # 35
            16 	,  # 36
            147 	,  # 37
            18 	,  # 38
            7 	,  # 39
            10 	,  # 40
            58 	,  # 41
            20 	,  # 42
            144 	,  # 43
            47 	,  # 44
            40 	,  # 45
            2 	,  # 46
            69 	,  # 47
            11 	,  # 48
            11 	,  # 49
            34 	,  # 50
            20 	,  # 51
            5 	,  # 52
            14 	,  # 53
            33 	,  # 54
            36 	,  # 55
            63 	,  # 56
            31 	,  # 57
            12 	,  # 58
            17 	,  # 59
            3 	,  # 60
            29 	,  # 61
            55 	,  # 62
            23 	,  # 63
            55 	,  # 64
            3 	,  # 65
            26 	,  # 66
            5 	,  # 67
            16 	,  # 68
            9 	,  # 69
            4 	,  # 70
            34 	,  # 71
            3 	,  # 72
            2 	,  # 73
            3 	,  # 74
            15 	,  # 75
            1 	,  # 76
            3 	,  # 77
            6 	,  # 78
            3 	,  # 79
            4 	,  # 80
            11 	,  # 81
            14 	,  # 82
            6 	,  # 83
            3 	,  # 84
            5 	,  # 85
            4 	,  # 86
            2 	,  # 87
            2 	,  # 88
            9 	,  # 89
            1 	,  # 90
            7 	,  # 91
            2 	,  # 92
            1 	,  # 93
            2 	,  # 94
            2 	,  # 95
            9 	,  # 96
            5 	,  # 97
            1 	,  # 98
            2 	,  # 99
            4 	,  # 100
            7 	,  # 101
            3 	,  # 102
            5 	,  # 103
            8 	,  # 104
            2 	,  # 105
            6 	,  # 106
            4 	,  # 107
            9 	,  # 108
            1 	,  # 109
            2 	,  # 110
            1 	,  # 111
            1 	,  # 112
            1 	,  # 113
            1 	,  # 114
            2 	,  # 115
            4 	,  # 116
            1 	,  # 117
            3 	,  # 118
            6 	,  # 119
            1 	,  # 120
            1 	,  # 121
            1 	,  # 122
            1 	,  # 123
            1 	,  # 124
            1 	,  # 125
            1 	,  # 126
            4 	,  # 127
            5 	,  # 128
            1 	,  # 129
            3 	,  # 130
            4 	,  # 131
            2 	,  # 132
            1 	,  # 133
            2 	,  # 134
            4 	,  # 135
            2 	,  # 136
            2 	,  # 137
            1 	,  # 138
            3 	,  # 139
            2 	,  # 140
            1 	,  # 141
            2 	,  # 142
            2 	,  # 143
            1 	,  # 144
            4 	,  # 145
            1 	,  # 146
            1 	,  # 147
            1 	,  # 148
            1 	,  # 149
            1 	,  # 150
            3 	,  # 151
            3 	,  # 152
            1 	,  # 153
            1 	,  # 154
            1 	,  # 155
            1 	,  # 156
            1 	,  # 157
            1 	,  # 158
            3 	,  # 159
            2 	,  # 160
            1 	,  # 161
            2 	,  # 162
            1 	,  # 163
            1 	,  # 164
            1 	,  # 165
            1 	,  # 166
            1 	,  # 167
            1 	,  # 168
            1 	,  # 169
            1 	,  # 170
            1 	,  # 171
            1 	,  # 172
            3 	,  # 173
            1 	,  # 174
            1 	,  # 175
            1 	,  # 176
            1 	,  # 177
            1 	,  # 178
            1 	,  # 179
            2 	,  # 180
            1 	,  # 181
            1 	,  # 182
            1 	,  # 183
            1 	,  # 184
            1 	,  # 185
            1 	,  # 186
            1 	,  # 187
            1 	,  # 188
            1 	,  # 189
            1 	,  # 190
            2 	,  # 191
            1 	,  # 192
            1 	,  # 193
            1 	,  # 194
            1 	,  # 195
            1 	,  # 196
            1 	,  # 197
            1 	,  # 198
            1 	,  # 199
            1 	,  # 200
            1 	,  # 201
            1 	,  # 202
            1 	,  # 203
            1 	,  # 204
            1 	,  # 205
            1 	,  # 206
            1 	,  # 207
            1 	,  # 208
            1 	,  # 209
            1 	,  # 210
            1 	,  # 211
            1 	,  # 212
            1 	,  # 213
            1 	,  # 214
            1 	,  # 215
            1 	,  # 216
            1 	,  # 217
            1 	,  # 218
            1 	,  # 219
            1 	,  # 220
            1 	,  # 221
            1 	,  # 222
            1 	,  # 223
            1 	,  # 224
            1 	,  # 225
            1 	,  # 226
            1 	,  # 227
            1 	,  # 228
            1 	,  # 229
            1 	,  # 230
            1 	,  # 231
            1 	,  # 232
            1 	,  # 233
            1 	,  # 234
            1 	,  # 235
            1 	,  # 236
            1 	,  # 237
            1 	,  # 238
            1 	,  # 239

        ]
        assert 0 <= acc <= 1
        self.now_batch = normal_batch
        # if acc < 0.75:
        #     # self.now_batch = [32] * self.n
        #     self.now_batch = normal_batch
        # elif acc < 0.8:
        #     self.now_batch = [3] * self.n
        # elif acc < 0.85:
        #     # self.now_batch = super_batch
        #     self.now_batch = [2] * self.n
        #
        # elif acc <= 1:
        #      self.now_batch= [1] * self.n

        if wrong_acc is not None and acc >= 0.75:
            wrong_acc_dict = {}
            for i, value in enumerate(wrong_acc):
                #  (value * 221) / normal_batch[1] 各类本身的错误率per wrong count/ per class
                self.now_batch[i] = int(self.now_batch[i] * (value * 240 / normal_batch[i]) + 1)
                wrong_acc_dict[i] = value

            print('val acc:%.4f,wrong acc：' % acc, wrong_acc_dict)

        return self.now_batch

def get_sliceCSVbyClassify_V4(label='label', classify_count=21, split=0.8):
    # 2020-4-24 classify_count 输入label的list

    # 读取数据
    tmp_a = pd.read_csv(os.path.join(DATA_PATH, DATA_ID, 'train.csv'))
    tmp_b = tmp_a.sample(frac=1)

    label_list = tmp_b['label'].values
    title_list = tmp_b['title'].values
    text_list = tmp_b['text'].values

    # 划分训练集和校验集
    all_size = len(label_list)

    # step 2 : 筛选 csv

    list_path_train, list_path_test = [], []
    # for epoch in range(classify_count):
    for epoch,value in enumerate(classify_count):
        # 根据label来筛选
        index = tmp_b[label] == value
        tmp_c = tmp_b[index]
        cut_length = int(len(tmp_c) * split)
        a = tmp_c[: cut_length]
        b = tmp_c[cut_length:]

        path_train = 'wangyi-train-classfy-' + str(epoch) + '.csv'
        a.to_csv(os.path.join(DATA_PATH, DATA_ID, path_train), index=False)
        list_path_train.append(path_train)

        path_test = 'wangyi-test-classfy-' + str(epoch) + '.csv'
        b.to_csv(os.path.join(DATA_PATH, DATA_ID, path_test), index=False)
        list_path_test.append(path_test)

        print('classfy-', epoch, ' : train and test.csv save OK!')

    return list_path_train, list_path_test

def getDatasetListByClassfy_V5(classify_count=21):
    # 2020-3-21 flyai改版本了，这是为了适应

    xx, yy = get_sliceCSVbyClassify_V4(classify_count=classify_count, split=train_vs_val)
    list_train = []
    list_val = []
    train_total_list = []
    val_total_list = []
    for epoch in range(len(classify_count)):
        time_0 = clock()
        # 读取数据
        tmp_train = pd.read_csv(os.path.join(DATA_PATH, DATA_ID, xx[epoch]))
        tmp_val = pd.read_csv(os.path.join(DATA_PATH, DATA_ID, yy[epoch]))

        # dataset = Lib(source=readCustomCsv_V3(xx[epoch], yy[epoch]), epochs=10)
        list_train.append(tmp_train)
        list_val.append(tmp_val)
        train_total_list.append(len(tmp_train))
        val_total_list.append(len(tmp_val))
        print('class-', epoch, ' 的data 建立成功, 耗时：%.1f 秒' % (clock() - time_0), '; train_length:',
              len(tmp_train), '; val_length:', len(tmp_val))

    return list_train, list_val, train_total_list, val_total_list

class DatasetByWangyi():
    def __init__(self, n):
        self.num_classes = n # n是label unique 的list
        self.dropout = 0.5

        time_0 = clock()
        self.train_pd_list, self.val_pd_list, self.train_total_list, self.val_total_list = getDatasetListByClassfy_V5(
            classify_count=n)
        self.train_step_list = [0] * len(n)
        self.val_step_list = [0] * len(n)

        print('全部分类的flyai dataset 建立成功, 耗时：%.1f 秒' % (clock() - time_0))

        self.train_batch_List = []
        self.val_batch_size = []
        self.data_dict_x = {}
        self.data_dict_y = {}
        self.read_All_to_Memory()

    def set_Batch_Size(self, train_size, val_size):
        self.train_batch_List = train_size
        self.val_batch_size = val_size

    def read_All_to_Memory(self, multitask=False):
        '''
        # 读取数据
        time_1 = clock()
        tmp_a = pd.read_csv(os.path.join(DATA_PATH, DATA_ID, 'train.csv'))
        label_list = tmp_a['label'].values
        title_list = tmp_a['title'].values
        text_list = tmp_a['text'].values
        # 生成x,y，以dict形式存在
        if multitask:
            pass
        else:
            for i, image in enumerate(image_path_list):
                self.data_dict_x[image] = get_1_x_data(image)
                self.data_dict_y[image] = get_1_y_data(label_list[i])
        print('全部图片加载到内存, 耗时：%.1f 秒' % (clock() - time_1))
        return self.data_dict_x, self.data_dict_y

        '''
        pass

    def get_Next_Batch(self):
        # 平衡输出45类数据
        train = self.get_Next_Train_Batch_fromMemory()
        val = self.get_Next_Val_Batch_fromMemory()
        return train ,val

    def get_Next_Train_Batch_fromMemory(self):
        # 平衡输出45类数据
        value_list = []
        # 改成生成list
        for iters in range(len(self.num_classes)):
            for i in range(self.train_batch_List[iters]):
                # 读取数据
                if len(self.train_pd_list[iters]['label'])==0:
                    continue
                # value = self.train_pd_list[iters]['label'].values[self.train_step_list[iters]]
                value = self.train_pd_list[iters].values[self.train_step_list[iters]]
                # print(value)
                value_list.append(value)
                # 修改游标
                self.train_step_list[iters] += 1
                self.train_step_list[iters] = self.train_step_list[iters] % self.train_total_list[iters]
        value_list = np.array(value_list)
        df = pd.DataFrame(value_list)
        df.columns = ['label', 'title', 'text']
        return df

    def get_Next_Val_Batch_fromMemory(self):
        value_list = []
        for iters in range(len(self.num_classes)):
            for i in range(self.val_batch_size[iters]):
                # 读取数据
                if len(self.val_pd_list[iters]['label'])==0:
                    continue
                value = self.val_pd_list[iters].values[self.val_step_list[iters]]
                value_list.append(value)
                # 修改游标
                self.val_step_list[iters] += 1
                self.val_step_list[iters] = self.val_step_list[iters] % self.val_total_list[iters]
        value_list = np.array(value_list)
        df = pd.DataFrame(value_list)
        df.columns = ['label', 'title', 'text']
        return df

def label_smoothing(inputs, epsilon=0.1):
    return (1.0 - epsilon) * inputs + epsilon / num_classes

class drawMatplotlib():
    def __init__(self):
        self.path = None
        self.train_acc_list = []  # x轴，对应每个epoch
        self.val_acc_list = []  # x轴，对应每个epoch
        self.f1_score = []  # x轴，对应每个epoch
        self.train_loss_list = []  # 对应每个epoch
        self.train_loss_list_y = []  # 每次batch训练的train acc
        self.val_loss_list = []  # 对应每个epoch
        self.learn_rate_list_y = []  # 收集用来matplotlib
        self.step_train_x = []  # 收集用来matplotlib
        self.step_val_x = []
        self.epoch_train_x = [] #acc,loss 的y轴坐标
        self.train_length_list = [] #acc,loss 的y轴坐标

    def set_path(self, path):
        self.path = path

    def showPlt(self, best_score_by_acc=0, best_score_by_loss=999, best_epoch=1, best_score_class=None):
        if best_score_class is not None:
            best_score_by_acc = best_score_class.best_score_by_acc
            best_score_by_loss = best_score_class.best_score_by_loss
            best_epoch = best_score_class.best_epoch
            best_f1_score = best_score_class.best_f1_score
        plt.clf()
        plt.figure('train and validate Accuracy')
        plt.figure(figsize=(12 + int(len(self.epoch_train_x) / 10), 8))
        plt.subplot(2, 2, 1)
        if best_score_by_acc != 0:
            plt.title('best: acc:%.4f, loss:%.4f, epoch:%d, f1_score:%.4f' % (
            best_score_by_acc, best_score_by_loss, best_epoch + 1, best_f1_score))
        else:
            plt.title('do not satisfy best_score condition')
        plt.xlabel('Epochs')
        plt.ylabel('Accuracy')
        plt.plot(self.epoch_train_x, self.train_acc_list, label='train_acc')
        plt.plot(self.epoch_train_x, self.val_acc_list, label='val_acc')
        plt.plot(self.epoch_train_x, self.f1_score, label='f1_score')
        plt.legend(['train_acc', 'val_acc', 'f1_score'], loc='upper left')

        plt.subplot(2, 2, 2)
        plt.xlabel('Epochs')
        plt.ylabel('Loss')
        plt.plot(self.epoch_train_x, self.train_loss_list, label='train_loss')
        plt.plot(self.epoch_train_x, self.val_loss_list, label='val_loss')
        # plt.plot(self.step_train_x, self.train_loss_list_y, label='per_train_loss')
        plt.legend(['train_loss', 'val_loss', 'per_train_loss'], loc='upper left')

        plt.subplot(2, 2, 3)
        plt.xlabel('Epochs')
        plt.ylabel('learn rate')
        plt.plot(self.step_train_x, self.learn_rate_list_y, label='learn_rate')
        plt.legend(['learn_rate'], loc='upper left')

        plt.subplot(2, 2, 4)
        plt.xlabel('Epochs')
        plt.ylabel('train length')
        plt.bar(self.epoch_train_x, self.train_length_list, label='train_length', align='center', width=0.8)
        plt.legend(['train_length'], loc='upper left')

        if self.path is not None:
            plt.savefig(self.path)
        plt.show()  # You must call plt.show() to make graphics appear.

class bestScore():
    def __init__(self):
        self.best_score_by_acc = 0.
        self.best_score_by_loss = 999.
        self.best_epoch = 0
        self.best_f1_score = 0
        # 保存最佳model的精准度，比如1%的准确范围写1,若2%的保存范围写2
        self.save_boundary = 0.1

    def judge_and_save(self, val_acc, val_loss, epoch, f1_score=None):

        if val_acc > 0.30:
            if f1_score is not None:
                if f1_score >= self.best_f1_score:
                    self.best_score_by_acc = val_acc
                    self.best_score_by_loss = val_loss
                    self.best_epoch = epoch
                    self.best_f1_score = f1_score
                    return True
            elif round(self.best_score_by_acc / self.save_boundary, 2) < round(
                    val_acc / self.save_boundary, 2):
                self.best_score_by_acc = val_acc
                self.best_score_by_loss = val_loss
                self.best_epoch = epoch
                print('【保存了best： acc提升】')
                return True

            elif round(self.best_score_by_acc / self.save_boundary, 2) == round(
                    val_acc / self.save_boundary, 2):
                if round(self.best_score_by_loss / self.save_boundary, 2) >= round(
                        val_loss / self.save_boundary, 2):
                    self.best_score_by_acc = val_acc
                    self.best_score_by_loss = val_loss
                    self.best_epoch = epoch
                    print('【保存了best：acc相同，loss降低】')
                    return True

        return False

    def get_now_best(self):
        return self.best_score_by_acc, self.best_score_by_loss, self.best_epoch

    def print_best_now(self):
        if self.best_score_by_acc == 0:
            print('未能满足best_score的条件')
        else:
            print(
                '当前【best】:acc:%.4f, loss:%.4f, epoch:%d, f1_score:%.4f' % (
                self.best_score_by_acc, self.best_score_by_loss, self.best_epoch + 1, self.best_f1_score))

    def print_best_final(self):
        print('best_score_by_acc :%.4f' % self.best_score_by_acc)
        print('best_score_by_loss :%.4f' % self.best_score_by_loss)
        print('best_score at epoch:%d' % (self.best_epoch + 1))
        print('best_f1_score:%.4f' % self.best_f1_score)

def get_nubclass_from_csv():
    readcsv = pd.read_csv(os.path.join(DATA_PATH, 'MedicalClass/train.csv'))
    file_unique = readcsv['label'].unique()
    list_unique = file_unique.tolist()
    return list_unique

if __name__ == '__main__':
    num_classes = len(get_nubclass_from_csv())
    dataset_wangyi = DatasetByWangyi(get_nubclass_from_csv())
    dataset_wangyi.set_Batch_Size([1]*209,[1]*209)
    train ,val =dataset_wangyi.get_Next_Batch()
    print(train)


import numpy as np

def export_trajectory(labels, trajectory, path):
    """
    Exports a trajectory in xyz format

    Parameters
    ----------
    labels : list
        A list containing the labels of the atom

    trajectory : list[np.ndarray]
        A list containing the xyz np.ndarrays

    path : str
        The path to the export file
    """

    n = len(labels)
    labels = np.array(labels).reshape((n,1))

    with open(path, 'wb') as file:
        for xyz in trajectory:
            file.write(str.encode("%s\n" %n))
            file.write(str.encode("label x y z\n"))

            with_labels = np.concatenate((labels, xyz), axis=1)
            np.savetxt(file, with_labels, delimiter=" ", fmt = '%s')


from typing import List

class Solution:
    def rob(self, nums: List[int]) -> int:
        # 思路是排列所有可能，取最大值
        if len(nums) == 0:
            return 0

        limit = len(nums)
        # lst = [0]
        max_result = -1
        num = nums[0]

        def solve(start):
            nonlocal max_result, num
            fired = False
            for i in range(start + 2, limit):
                # lst.append(i)
                num += nums[i]
                solve(i)
                num -= nums[i]
                # lst.pop()
                fired = True

            if not fired:
                # ret = sum(map(lambda x: nums[x], lst))
                # print(num)
                max_result = max(max_result, num)

        solve(0)
        if len(nums) > 1:
            num = nums[1]
            solve(1)
        print(max_result)
        return max_result


import discord
import os
from discord.ext import commands

prefixes = ['<@!757743672379834448> ', 'lol ', 'lol']
bot = commands.Bot(command_prefix=prefixes)
bot.remove_command('help')

def is_it_me(ctx):
    return ctx.author.id == 475315771086602241

@bot.event
async def on_ready():
    print('Bot is online')

@bot.command()
@commands.check(is_it_me)
async def cog(ctx, typeOf, extension):
    if typeOf == 'load':
        bot.load_extension(f'cogs.{extension}')
        await ctx.send(f'Loaded **{extension}**!')
    if typeOf == 'unload':
        bot.unload_extension(f'cogs.{extension}')
        await ctx.send(f'Unloaded **{extension}**!')
    if typeOf == 'reload':
        bot.unload_extension(f'cogs.{extension}')
        bot.load_extension(f'cogs.{extension}')
        await ctx.send(f'Reloaded **{extension}**!')

for filename in os.listdir('./cogs'):
    if filename.endswith('.py'):
        bot.load_extension(f'cogs.{filename[:-3]}')

bot.run(os.environ.get('BOT_TOKEN'))


import configparser
import json
import os
from google.cloud import bigquery
from google.oauth2 import service_account

config = configparser.ConfigParser()
config.read('config/bigquery.ini')
ynab_config = config['YNAB']

credentials = service_account.Credentials.from_service_account_file(
    ynab_config['ServiceAccountKey'])
client = bigquery.Client(ynab_config['ProjectID'], credentials)

entities = [
    'accountMappings',
    'accounts',
    'masterCategories',
    'monthlyBudgets',
    'payees',
    'scheduledTransactions',
    'transactions'
]

def open_budget():
    """Opens the YNAB4 budget file and sends each entity to another function to create
        a newline JSON file.
    """
    with open(ynab_config['BudgetFile']) as json_file:
        data = json.load(json_file)

        for entity in entities:
            convert_to_newline_json(entity, data[entity])

def convert_to_newline_json(entity: str, data: list):
    """Write each record from YNAB4's budget for this entity into a new line
        in JSON, named after the entity. This will just write to your local disk.

    Args:
        entity (str): Name of this entity, e.g. 'accounts', 'transactions'.
        data (list): List of records from the YNAB4 budget file for this entity.
    """
    with open(''.join((entity, '.json')), 'w') as f:
        for line in data:
            json.dump(line, f)
            f.write('\n')

def upload_to_bq():
    """Uploads each JSON file for YNAB4 entities into BigQuery. Presets are:
        Write Disposition: WRITE_TRUNCATE
        Schema: Auto-detect

    Raises:
        Exception: Throw an exception if the JSON file can't be uploaded and tell us
            which entity threw the error.
    """
    dataset_ref = client.dataset(ynab_config['Dataset'])
    job_config = bigquery.LoadJobConfig()

    for entity in entities:
        filename = ''.join((entity, '.json'))
        if os.stat(filename).st_size == 0:
            continue

        table_ref = dataset_ref.table(entity)
        job_config.source_format = bigquery.SourceFormat.NEWLINE_DELIMITED_JSON
        job_config.write_disposition = bigquery.WriteDisposition.WRITE_TRUNCATE
        job_config.autodetect = True

        try:
            with open(filename, 'rb') as source_file:
                job = client.load_table_from_file(
                    source_file,
                    table_ref,
                    location=ynab_config['Location'],
                    job_config=job_config
                )
        except Exception as e:
            msg = "Problem with entity: {}. {}".format(entity, e)
            raise Exception(msg)

        job.result()

        print("Loaded {} rows into {}:{}".format(
            job.output_rows, ynab_config['Dataset'], entity))

def clean_up_files():
    """Iterate through each YNAB4 entity and delete the JSON file named after it from
        your local disk.
    """
    for entity in entities:
        filename = ''.join((entity, '.json'))
        os.remove(filename)


N = int(input())
a = list(map(int, input().split()))
M = 10**5
c = [0]*(M+1)
for ai in a:
    c[ai] += 1
ans = 0
for i in range(1, M):
    ans = max(ans, c[i-1]+c[i]+c[i+1])

print(ans)


import json as j
import yaml as y

def itemenc(item, cnt=1):
	encs = "enchantments";
	jsond = dict()
	if item.find("(")==-1:
		jsond["type"] = item.upper();
		jsond["amount"] = cnt;
	else:
		jsond["type"] = item[:item.find("(")].upper();
		jsond["amount"] = cnt;
		jsond[encs] = list();
		ench = item[item.find("(")+1:item.find(")")];
		ench = ench.split(sep=",");
		for i in range(len(ench)):
			ench[i] = ench[i].strip();
			ench[i] = ench[i].split(sep="+");
			jsond[encs].append(dict());
			jsond[encs][-1]["type"] = ench[i][0];
			jsond[encs][-1]["level"] = int(ench[i][1]);
	return j.dumps(jsond);

def kitenc(item, name, items):
	kit = dict();
	kit["symbol"] = dict();
	kit["symbol"]["item"] = item;
	kit["symbol"]["name"] = name;
	kit["items"] = items;
	return kit;

def main(ifile, ofile):
	item = str();
	case = int(ifile.readline().strip("\n"));
	kits = dict();
	for cntk in range(case):
		pro = ifile.readline();
		while pro == '\n':
			pro = ifile.readline();
		pro = pro.strip("\n");
		if pro.find("(")==-1:
			pro = pro.split();
			citem = int(pro[0]);
			idn = pro[1];
			item = itemenc(pro[2]);
			name = pro[3];
		else:
			pros = pro.split();
			citem = int(pros[0]);
			idn = pros[1];
			name = pros[-1];
			item = str();
			for i in pros[2:-1]:
				item += i;
			item = itemenc(item);
		items = list();
		for cnti in range(citem):
			kitem = ifile.readline().strip("\n");
			ind = kitem.rfind(' ');
#			sitem = kitem.split();
			if (ind!=-1) and (kitem[ind+1:].isdigit()):
				items.append(itemenc(kitem[:ind], int(kitem[ind+1:])));
			else:
				items.append(itemenc(kitem));

		kit = kitenc(item, name, items);
		kits[idn] = kit;

	ofile.write(y.dump({"kits":kits}));

if __name__ == "__main__":
	ifile = open("kits.in", "r");
	ofile = open("kits.yml", "w");
#	ifile = open(input("input file:"), "r");
#	ofile = open(input("output file:"), "w");
	main(ifile, ofile);
	ifile.close();
	ofile.close();
	print("解析完成，已存储为 kits.yml\n是否写入 ./plugins/UhcCore/kits.yml [Y/n] : ", end='')
	if input()[0]=='Y':
		ifile = open("kits.in", "r");
		ofile = open("plugins/UhcCore/kits.yml", "w");
		main(ifile, ofile);
		ifile.close();
		ofile.close();


'''
Modified from Ray Wu's code
https://github.com/raywu0123
'''

import requests
import pprint
import os

class LabClient:

    def __init__(self, url, student_id):
        self.base_url = url
        self.get_url = f'{self.base_url}population/{student_id}/'
        self.post_url = f'{self.base_url}api/{student_id}'

    def get_population(self, filename, dir_name):
        with open(os.path.join(dir_name, filename), 'w') as f:
            r = requests.get(f'{self.get_url}{filename}')
            f.write(r.text)

    def post_mpm(self, file_path, generation):
        with open(file_path, 'rb') as f:
            r = requests.post(
                self.post_url,
                data={'gen': generation},
                files={'file': f},
            )
        fitness_str = r.json()['fitness']
        target = "Fitness:(Max/Mean/Min):"
        target_idx = fitness_str.find(target)
        max_fitness = float(fitness_str[target_idx + len(target):target_idx + len(target)+5])
        return max_fitness


# -*- coding: utf-8 -*-
import pylab as plt
import numpy as np

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from PyQt5.QtWidgets import QSizePolicy

class Graph(FigureCanvasQTAgg):
    def __init__(self, parent=None, width=10, height=10, dpi=100):
        figure = plt.Figure(figsize=(width, height), dpi=dpi)
        figure.subplots_adjust(left   = 0.0,
                               right  = 1.0,
                               top    = 1.0,
                               bottom = 0.0,
                               wspace = 0.0,
                               hspace = 0.0)
        super(Graph, self).__init__(figure)

        self.parent = parent
        self.figure = figure

        # Fill the area with the graph
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.axes = figure.add_subplot(111)
        self.axes.set_xticks(())
        self.axes.set_yticks(())

        self.im = None

        self.is_interactive = True
        self.corners_callback = None
        self.corners = None

        self.scatter_plots = []

        figure.canvas.mpl_connect("button_press_event", self.button_press_event)

    def clear_corners(self):
        self.corners = None

        # Clear scatterplot overlays if they exist
        if len(self.scatter_plots) > 0:
            for plot in self.scatter_plots:
                plot.remove()

        self.scatter_plots = []
        self.draw()

    def button_press_event(self, event):
        if not self.is_interactive:
            return

        # Right-click erases scatterplot overlays
        if event.button == 3:
            self.clear_corners()

        # Left-click adds point markers
        elif event.button == 1 and event.xdata and event.ydata:
            p = np.array([event.xdata, event.ydata])

            if self.corners is None:
                self.corners = np.array([p])

            else:
                temp = np.vstack((self.corners, p))
                self.corners = temp

            draw_plot = True
            if self.corners_callback:
                draw_plot = self.corners_callback()

            if draw_plot and self.corners is not None:
                # Draw new overlay
                plot = self.axes.scatter(*zip(*self.corners), c="r", s=2)
                self.scatter_plots.append(plot)
                self.draw()

    def imshow(self, im):
        # Fixes the issue of plot auto-rescaling
        # When overlaying scatterplot points
        self.axes.set_xlim([0, im.shape[1]])
        self.axes.set_ylim([im.shape[0], 0])

        self.im = im
        self.axes.imshow(im)
        self.draw()


import os
from pathlib import Path

from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding

def encrypt_dataset(
    rsa_keys_dir: Path, dataset_dir: Path, output_dir: Path
) -> None:
    """
    Encrypts a dataset as follows:
        1. Generates the symmetric key for this dataset.
        2. Encrypts the dataset using the symmetric key.
        3. Encrypts the symmetric key using the public rsa key.
    """

    if not rsa_keys_dir.exists():
        print("The RSA keys directory has to exist")
        raise SystemExit(1)

    if not dataset_dir.exists():
        print(
            "The directory containing the dataset files to encrypt has to exist."
        )
        raise SystemExit(1)

    if not output_dir.exists():
        os.makedirs(output_dir)

    public_key_location = rsa_keys_dir / "microdata_public_key.pem"

    if not public_key_location.is_file():
        print(f"Public key {public_key_location} not found")
        raise SystemExit(1)

    # Read public key from file
    with open(public_key_location, "rb") as key_file:
        public_key = serialization.load_pem_public_key(
            key_file.read(), backend=default_backend()
        )

    csv_files = [
        file for file in dataset_dir.iterdir() if file.suffix == ".csv"
    ]

    if len(csv_files) == 0:
        print(f"No csv files found in {dataset_dir}")
        raise SystemExit(1)

    if len(csv_files) > 1:
        print(f"There should only be one csv file in {dataset_dir}")
        raise SystemExit(1)

    csv_file = csv_files[0]
    dataset_name = csv_file.stem

    if dataset_name != dataset_dir.stem:
        print(
            f"The csv file name {dataset_name} should match "
            f"the dataset directory name {dataset_dir.stem}."
        )
        raise SystemExit(1)

    dataset_output_dir = output_dir / dataset_name
    os.makedirs(dataset_output_dir)

    encrypted_file = dataset_output_dir / f"{dataset_name}.csv.encr"
    encrypted_symkey_file = dataset_output_dir / f"{dataset_name}.symkey.encr"

    # Generate and store symmetric key for this file
    symkey = Fernet.generate_key()

    # Encrypt csv file
    with open(csv_file, "rb") as file:
        data = file.read()  # Read the bytes of the input file

    fernet = Fernet(symkey)
    encrypted = fernet.encrypt(data)

    with open(encrypted_file, "wb") as file:
        file.write(encrypted)

    print(f"Csv file {csv_file} encrypted into {encrypted_file}")

    encrypted_sym_key = public_key.encrypt(
        symkey,
        padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA256()),
            algorithm=hashes.SHA256(),
            label=None,
        ),
    )

    # Store encrypted symkey to file
    with open(encrypted_symkey_file, "wb") as file:
        file.write(encrypted_sym_key)

    print(f"Key file for {csv_file} encrypted into {encrypted_symkey_file}")
    print("Encryption done!")


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Apr 30 18:09:16 2020

@author: piumallick
"""
# Problem 6: Climbing Stairs
'''
You are climbing a stair case. It takes n steps to reach to the top.

Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?

Note: Given n will be a positive integer.

Example 1:

Input: 2
Output: 2
Explanation: There are two ways to climb to the top.
1. 1 step + 1 step
2. 2 steps
Example 2:

Input: 3
Output: 3
Explanation: There are three ways to climb to the top.
1. 1 step + 1 step + 1 step
2. 1 step + 2 steps
3. 2 steps + 1 step
'''

def climbStairs(n):
    if (n <= 2):
        return n

    a = 1
    b = 2
    result = 0
    for i in range(2, n):
        result = a + b
        a = b
        b = result

    return result

def climbStairs2(n):
    """
    :type n: int
    :rtype: int
    """
    c = [1, 1]
    for i in range(2, n+1):
        c.append(c[i-1] + c[i-2])
    return c[n]

# Testing
n = 0
print(climbStairs2(n))


from PyQt5.QtWidgets import QAction
from PyQt5.QtGui import QIcon

from modules.deck.QGui.QDeckStackedWidget import QDeckStackedWidget

import functools

class Menu(object):
    def __init__(self, context, menubar):
        self.context = context

        deckMenu = menubar.addMenu('&Deck')

        decksManagerAction = QAction(QIcon.fromTheme("document-properties"), '&Decks Manager', context)
        decksManagerAction.setStatusTip('See an Overview of all Decks / edit / create Decks')
        decksManagerAction.triggered.connect(functools.partial(self.addDecksManagerTab, context))

        deckMenu.addAction(decksManagerAction)

    def addDecksManagerTab(self, context):
        decks_widget = QDeckStackedWidget().deckWidget()
        decks_widget.set_tab_text.connect(self.setTabText)
        context.addNewCustomTab(decks_widget, 'decks manager')

    def setTabText(self, text):
        self.context.setTabText(self.context.tab_widget.currentIndex(), text)


from __future__ import annotations

import os
from typing import Any, AnyStr, AsyncGenerator, Dict, Generator, List, Tuple, TYPE_CHECKING, Union

if TYPE_CHECKING:
    from werkzeug.datastructures import Headers  # noqa: F401

    from .wrappers.response import Response  # noqa: F401

FilePath = Union[bytes, str, os.PathLike]

# The possible types that are directly convertible or are a Response object.
ResponseValue = Union[
    "Response",
    AnyStr,
    Dict[str, Any],  # any jsonify-able dict
    AsyncGenerator[bytes, None],
    Generator[bytes, None, None],
]
StatusCode = int

# the possible types for an individual HTTP header
HeaderName = str
HeaderValue = Union[str, List[str], Tuple[str, ...]]

# the possible types for HTTP headers
HeadersValue = Union["Headers", Dict[HeaderName, HeaderValue], List[Tuple[HeaderName, HeaderValue]]]

# The possible types returned by a route function.
ResponseReturnValue = Union[
    ResponseValue,
    Tuple[ResponseValue, HeadersValue],
    Tuple[ResponseValue, StatusCode],
    Tuple[ResponseValue, StatusCode, HeadersValue],
]


from es2 import sin, fact

if __name__ == "__main__":
    # for n in range(10):
    #     print("sin({}, {}) => {:.4f}".format(.5, n, sin(.5, n)))

    # print(sin.cache)

    for n in [5, 7, 10, 8, 12, 9]:
        print("fact({}) => {}".format(n, fact(n)))


from dataclasses import fields
from unicodedata import category
from django import forms
from blog.models import *
from lappyng_app.models import *
from django.core import validators

class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ('name', 'email', 'body')

        widgets = {
            'name': forms.TextInput(attrs={'class': 'form-control', 'placeholder':'Enter Name'}),
            'email': forms.TextInput(attrs={'class': 'form-control', 'placeholder':'Enter Email'}),
            'body': forms.Textarea(attrs={'class': 'form-control'}),

        }

class ProductReviewForm(forms.ModelForm):
    ONE = '10'
    TWO = '20'
    THREE = '30'
    FOUR = '40'
    FIVE = '50'
    SIX = '60'
    SEVEN = '70'
    EIGHT = '80'
    NINE = '90'
    TEN = '100'
    CHOOSE = ''
    RATING_LIST = [
        (ONE, 1),
        (TWO, 2),
        (THREE, 3),
        (FOUR, 4),
        (FIVE, 5),
        (SIX, 6),
        (SEVEN, 7),
        (EIGHT, 8),
        (NINE, 9),
        (TEN, 10),
        (CHOOSE, 'Choose Rating'),
    ]

    full_name = forms.CharField(
                widget = forms.TextInput(
                    attrs={'class':'form-control', 'placeholder':'Fullname'}
                ),
                )
    email = forms.EmailField(
                widget = forms.EmailInput(
                    attrs={'class':'form-control', 'placeholder':'Email'}
                ),
                )
    rating = forms.CharField(
                widget = forms.Select(
                    attrs={'class':'form-control',},
                    choices=RATING_LIST,
                ),
                )

    review = forms.CharField(
                widget = forms.Textarea(
                    attrs={'class':'form-control',}
                ),
                )
    botcatcher = forms.CharField(
        required=False,
        widget=forms.HiddenInput,
        validators=[validators.MaxLengthValidator(0)])

    class Meta:
        model = ProductReview
        exclude = ('created_at', 'updated', 'product')

class ProductRequestForm(forms.ModelForm):
    name = forms.CharField(
                widget = forms.TextInput(
                    attrs={'class':'form-control', 'placeholder':'Fullname'}
                ),
                )
    email = forms.EmailField(
                widget = forms.EmailInput(
                    attrs={'class':'form-control', 'placeholder':'Email'}
                ),
                )
    phone = forms.CharField(
                widget = forms.TextInput(
                    attrs={'class':'form-control', 'placeholder':'Phone'}
                ),
                )
    description = forms.CharField(
                widget = forms.Textarea(
                    attrs={'class':'form-control',}
                ),
                )
    botcatcher = forms.CharField(
        required=False,
        widget=forms.HiddenInput,
        validators=[validators.MaxLengthValidator(0)])

    class Meta:
        model = ProductRequest
        exclude = ('created', 'modified', 'product')

class SearchForm(forms.ModelForm):
    title = forms.CharField(widget=forms.TextInput(
        attrs={'class':'form-control', 'placeholder':'Search your site'}
    ))
    category = forms.ModelChoiceField(
        queryset=Category.objects.all(),
        empty_label='All Categories',
        widget=forms.Select(attrs={'class':'categori-search-option'})
    )
    botcatcher = forms.CharField(
        required=False,
        widget=forms.HiddenInput,
        validators=[validators.MaxLengthValidator(0)])

    class Meta():
        model = Products
        fields = ['title', 'category']


from enum import Enum, auto

try:
    import CynanBotCommon.utils as utils
except:
    from ...CynanBotCommon.utils import utils

class PkmnCatchType(Enum):

    GREAT = auto()
    NORMAL = auto()
    ULTRA = auto()

    @classmethod
    def fromStr(cls, text: str):
        if not utils.isValidStr(text):
            raise ValueError(f'text argument is malformed: \"{text}\"')

        text = text.lower()

        if text == 'great':
            return PkmnCatchType.GREAT
        elif text == 'normal':
            return PkmnCatchType.NORMAL
        elif text == 'ultra':
            return PkmnCatchType.ULTRA
        else:
            raise ValueError(f'unknown PkmnCatchType: \"{text}\"')

    def getSortOrder(self) -> int:
        if self is PkmnCatchType.GREAT:
            return 1
        elif self is PkmnCatchType.NORMAL:
            return 0
        elif self is PkmnCatchType.ULTRA:
            return 2
        else:
            raise RuntimeError(f'unknown PkmnCatchType: \"{self}\"')

    def toStr(self) -> str:
        if self is PkmnCatchType.GREAT:
            return 'great'
        elif self is PkmnCatchType.NORMAL:
            return 'normal'
        elif self is PkmnCatchType.ULTRA:
            return 'ultra'
        else:
            raise RuntimeError(f'unknown PkmnCatchType: \"{self}\"')


import pytest
import uuid

from typing import Optional

from freexgraph.standard_visitor import FindFirstVisitor
from freexgraph import GraphNode, FreExNode, FreExGraph

class NodeForTest(FreExNode):
    def accept(self, visitor) -> bool:
        return visitor.testing_visit(self)

def test_make_exec_graph():
    execution_graph = FreExGraph()
    id1 = f"id1_{uuid.uuid4()}"
    id2 = f"id2_{uuid.uuid4()}"
    id3 = f"id3_{uuid.uuid4()}"
    id3_bis = f"id3bis_{uuid.uuid4()}"
    id4 = f"id4_{uuid.uuid4()}"
    id5 = f"id5_{uuid.uuid4()}"

    execution_graph.add_node(FreExNode(id1)),
    execution_graph.add_node(FreExNode(id2, parents={id1})),
    execution_graph.add_node(FreExNode(id4, parents={id2})),
    execution_graph.add_node(FreExNode(id3, parents={id2, id4})),
    execution_graph.add_node(FreExNode(id3_bis, parents={id4})),
    execution_graph.add_node(FreExNode(id5, parents={id4, id3})),

    assert execution_graph._graph.has_node(id1)
    assert execution_graph.get_node(id1).depth == 1

    assert execution_graph._graph.has_node(id2)
    assert execution_graph.get_node(id2).depth == 2

    assert execution_graph._graph.has_node(id3)
    assert execution_graph.get_node(id3).depth == 4

    assert execution_graph._graph.has_node(id3_bis)
    assert execution_graph.get_node(id3_bis).depth == 4

    assert execution_graph._graph.has_node(id4)
    assert execution_graph.get_node(id4).depth == 3

    assert execution_graph._graph.has_node(id5)
    assert execution_graph.get_node(id5).depth == 5

def test_add_node_reserved_character():
    execution_graph = FreExGraph()
    id1 = f"id1::{uuid.uuid4()}"
    with pytest.raises(AssertionError):
        execution_graph.add_node(FreExNode(id1))
    id1 = f"id1:{uuid.uuid4()}"
    with pytest.raises(AssertionError):
        execution_graph.add_node(FreExNode(id1))

def test_get_not_existing(valid_basic_execution_graph):
    node: Optional[FreExNode] = valid_basic_execution_graph.get_node("NOT_EXISTING")
    assert node is None

def test_visitation(valid_basic_execution_graph, visitor_test, node_test_class):
    #
    #
    #     ,_____, id2
    #  id1         |
    #              |    ,----- id3
    #              |   /           \
    #              |  /             `___ id5
    #             id4 `--------------`
    #
    visitor_test.visit(valid_basic_execution_graph.root)

    assert visitor_test.end
    assert len(visitor_test.visited) == 5
    assert visitor_test.visited[0].startswith("id1_")
    assert visitor_test.visited[1].startswith("id2_")
    assert visitor_test.visited[2].startswith("id4_")
    assert visitor_test.visited[3].startswith("id3_")
    assert visitor_test.visited[4].startswith("id5_")

    # check that modification of the node
    id5 = visitor_test.visited[4]
    node_5 = valid_basic_execution_graph.get_node(id5)
    assert node_5.metadata is None
    assert node_5.fork_id is None
    assert sorted(node_5.parents) == sorted(
        {visitor_test.visited[3], visitor_test.visited[2]}
    )

    valid_basic_execution_graph.replace_node(
        node_test_class(
            id5,
            metadata="ChocoboForTheWin",
            parents={"ThisIdWouldMessUpEverything"},
            graph_ref=None,
            fork_id="Chocobo",
        )
    )

    node_5 = valid_basic_execution_graph.get_node(id5)
    assert node_5.metadata == "ChocoboForTheWin"
    assert node_5.fork_id is None
    assert sorted(node_5.parents) == sorted(
        {visitor_test.visited[3], visitor_test.visited[2]}
    )

# used only in test_visitation_custom_hook and never somewhere else
test_visitation_custom_hook_count = [0, 0]

def test_visitation_custom_hook(visitor_test, node_test_class):
    execution_graph = FreExGraph()
    id1 = f"id1_{uuid.uuid4()}"
    id2 = f"id2_{uuid.uuid4()}"
    id3 = f"id3_{uuid.uuid4()}"
    id3_bis = f"id3bis_{uuid.uuid4()}"
    id4 = f"id4_{uuid.uuid4()}"
    id5 = f"id5_{uuid.uuid4()}"

    execution_graph.add_node(node_test_class(id1)),
    execution_graph.add_node(node_test_class(id2, parents={id1})),
    execution_graph.add_node(node_test_class(id4, parents={id2})),
    execution_graph.add_node(node_test_class(id3, parents={id2, id4})),
    execution_graph.add_node(node_test_class(id3_bis, parents={id4})),
    execution_graph.add_node(node_test_class(id5, parents={id4, id3})),

    def hook(_):
        global test_visitation_custom_hook_count
        test_visitation_custom_hook_count[0] += 1

    def hook_2(_):
        global test_visitation_custom_hook_count
        test_visitation_custom_hook_count[1] += 1

    visitor_test.register_custom_hook(
        predicate=lambda n: n.id.startswith("id3"), hook=hook
    )
    visitor_test.register_custom_hook(
        predicate=lambda n: not n.id.startswith("id3"),
        hook=hook_2,
    )
    visitor_test.visit(execution_graph.root)

    assert visitor_test.end
    assert len(visitor_test.visited) == 6
    assert test_visitation_custom_hook_count[0] == 2
    assert test_visitation_custom_hook_count[1] == 4

def test_graph_node(valid_basic_execution_graph, visitor_test):
    #
    #                ida
    #                 |
    #                idb
    #              /  |
    #          idd    |
    #        /  |  \  |
    #      idc  |   GRAPH  ==> valid_basic_execution_graph
    #           |  /
    #          ide

    execution_graph = FreExGraph()
    ida = f"ida_{uuid.uuid4()}"
    idb = f"idb_{uuid.uuid4()}"
    idc = f"idc_{uuid.uuid4()}"
    id_graph = f"idg_{uuid.uuid4()}"
    idd = f"idd_{uuid.uuid4()}"
    ide = f"ide_{uuid.uuid4()}"

    execution_graph.add_node(NodeForTest(ida))
    execution_graph.add_node(NodeForTest(idb, parents={ida}))
    execution_graph.add_node(NodeForTest(idd, parents={idb}))
    execution_graph.add_node(
        GraphNode(id_graph, parents={idb, idd}, graph=valid_basic_execution_graph)
    )
    execution_graph.add_node(NodeForTest(idc, parents={idd}))
    execution_graph.add_node(NodeForTest(ide, parents={idd, id_graph}))

    visitor_test.visit(execution_graph.root)

    assert visitor_test.end
    assert len(visitor_test.visited) == 10
    assert visitor_test.visited[0].startswith("ida_")
    assert execution_graph.get_node(ida).depth == 1
    assert visitor_test.visited[1].startswith("idb_")
    assert execution_graph.get_node(idb).depth == 2
    assert visitor_test.visited[2].startswith("idd_")
    assert execution_graph.get_node(idd).depth == 3

    assert visitor_test.visited[3].startswith("idc_")

    assert execution_graph.get_node(idc).depth == 4
    assert execution_graph.get_node(id_graph).depth == 4

    assert visitor_test.visited[4].startswith("id1_")
    assert visitor_test.visited[5].startswith("id2_")
    assert visitor_test.visited[6].startswith("id4_")
    assert visitor_test.visited[7].startswith("id3_")
    assert visitor_test.visited[8].startswith("id5_")

    assert visitor_test.visited[9].startswith("ide_")
    assert execution_graph.get_node(ide).depth == 5

    assert len(visitor_test.inner_graph_started) == 1
    assert visitor_test.inner_graph_started[0].startswith(id_graph)
    assert visitor_test.inner_graph_started == visitor_test.inner_graph_ended

    # test find in graph node from root
    finder = FindFirstVisitor(lambda n: n.id.startswith("id3"))
    finder.visit(execution_graph.root)
    assert finder.found()
    assert finder.result.id.startswith("id3")

def test_add_nodes(node_list_complex_graph, visitor_test):
    execution_graph = FreExGraph()
    execution_graph.add_nodes(node_list_complex_graph)

    visitor_test.visit(execution_graph.root)

    assert visitor_test.end
    assert len(visitor_test.visited) == 13

def test_add_nodes_not_properly_connected_nodes(node_list_complex_graph):
    node_list_complex_graph.append(NodeForTest("X", parents={"NOT_EXISTING"}))
    execution_graph = FreExGraph()
    with pytest.raises(AssertionError):
        execution_graph.add_nodes(node_list_complex_graph)

def test_add_nodes_multiple_nodes_same_id(node_list_complex_graph):
    # K is already in graph
    assert "K" in [n.id for n in node_list_complex_graph]

    # adding another K fail
    node_list_complex_graph.append(NodeForTest("K"))
    execution_graph = FreExGraph()
    with pytest.raises(AssertionError):
        execution_graph.add_nodes(node_list_complex_graph)

def test_add_nodes_on_already_created_graph(valid_complex_graph, visitor_test):
    to_add = [
        NodeForTest("N", parents={"A", "K"}),
        NodeForTest("O", parents={"B", "I", "J"}),
        NodeForTest("P", parents={"N", "C"}),
    ]

    valid_complex_graph.add_nodes(to_add)

    visitor_test.visit(valid_complex_graph.root)

    assert visitor_test.end
    assert len(visitor_test.visited) == 16

def test_add_not_linked_nodes_on_already_created_graph(valid_complex_graph):
    to_add = [
        NodeForTest("X", parents={"A", "NOT_EXISTING"}),
    ]
    with pytest.raises(AssertionError):
        valid_complex_graph.add_nodes(to_add)

def test_delete_one_node(visitor_test):
    #
    #                ida
    #                 |
    #                idb
    #              /  |
    #          idd    |
    #        /  |  \  |
    #      idc  |    idx
    #           |  /
    #          ide

    execution_graph = FreExGraph()
    ida = f"ida_{uuid.uuid4()}"
    idb = f"idb_{uuid.uuid4()}"
    idc = f"idc_{uuid.uuid4()}"
    idx = f"idx_{uuid.uuid4()}"
    idd = f"idd_{uuid.uuid4()}"
    ide = f"ide_{uuid.uuid4()}"

    execution_graph.add_node(NodeForTest(ida))
    execution_graph.add_node(NodeForTest(idb, parents={ida}))
    execution_graph.add_node(NodeForTest(idd, parents={idb}))
    execution_graph.add_node(NodeForTest(idx, parents={idb, idd}))
    execution_graph.add_node(NodeForTest(idc, parents={idd}))
    execution_graph.add_node(NodeForTest(ide, parents={idd, idx}))

    visitor_test.visit(execution_graph.root)

    assert len(visitor_test.visited) == 6

    assert ide in visitor_test.visited

    # should only remove ide
    execution_graph.remove_node(ide)

    visitor_test.visit(execution_graph.root)

    assert len(visitor_test.visited) == 5

    assert ide not in visitor_test.visited

    assert ida == visitor_test.visited[0]
    assert idb == visitor_test.visited[1]
    assert idd == visitor_test.visited[2]
    assert idc == visitor_test.visited[3]
    assert idx == visitor_test.visited[4]

def test_delete_node_with_childs(visitor_test):
    #
    #                ida
    #                 |
    #                idb
    #              /  |
    #          idd    |
    #        /  |  \  |
    #      idc  |    idx
    #           |  /
    #          ide

    execution_graph = FreExGraph()
    ida = f"ida_{uuid.uuid4()}"
    idb = f"idb_{uuid.uuid4()}"
    idc = f"idc_{uuid.uuid4()}"
    idx = f"idx_{uuid.uuid4()}"
    idd = f"idd_{uuid.uuid4()}"
    ide = f"ide_{uuid.uuid4()}"

    execution_graph.add_node(NodeForTest(ida))
    execution_graph.add_node(NodeForTest(idb, parents={ida}))
    execution_graph.add_node(NodeForTest(idd, parents={idb}))
    execution_graph.add_node(NodeForTest(idx, parents={idb, idd}))
    execution_graph.add_node(NodeForTest(idc, parents={idd}))
    execution_graph.add_node(NodeForTest(ide, parents={idd, idx}))

    # should remove idc, ide and idx
    execution_graph.remove_node(idd)

    visitor_test.visit(execution_graph.root)

    assert len(visitor_test.visited) == 2

    assert ide not in visitor_test.visited

    assert ida == visitor_test.visited[0]
    assert idb == visitor_test.visited[1]

def test_predecessors_successors(valid_basic_execution_graph):
    v = FindFirstVisitor(lambda node: node.id.startswith("id3"))
    v.visit(valid_basic_execution_graph.root)

    assert v.found()
    assert v.result.id.startswith("id3")
    assert len(v.result.parents) == 2

    node_predecessors = v.result.get_predecessors()
    node_predecessors.sort(key=lambda n: n.id)
    assert len(node_predecessors) == 2
    assert node_predecessors[0].id.startswith("id2")
    assert node_predecessors[1].id.startswith("id4")

    node_predecessors = v.result.get_successors()
    assert len(node_predecessors) == 1
    assert node_predecessors[0].id.startswith("id5")

def test_middle_visitation_start(valid_complex_graph):
    v = FindFirstVisitor(lambda node: node.id == "F")
    v.visit(valid_complex_graph.root)

    f_node = v.result
    assert v.found()
    assert f_node.id == "F"

    # G and F are at the same level and thus are always executed on partial visitation
    find_g = FindFirstVisitor(lambda node: node.id == "G")

    # start visitation from F node [A, B, C, D, E] should not be visited
    v = FindFirstVisitor(lambda node: node.id in ["A", "B", "C", "D", "E"])
    v.visit(f_node)
    assert not v.found()
    find_g.visit(f_node)
    assert find_g.found()

    # start reverse visitation node [H, I, J, K, L, M] should not be visited
    v = FindFirstVisitor(lambda node: node.id in ["H", "I", "J", "K", "L", "M"])
    v.is_reversed = True
    v.visit(f_node)
    assert not v.found()
    find_g.visit(f_node)
    assert find_g.found()


from stat import S_ISDIR, S_ISREG, S_ISLNK
from os import listdir, stat, lstat
from os.path import abspath, join, splitext
from multiprocessing import Pool, cpu_count

from .parser import Parser
from .source_visitor import SourceVisitor
from .config import Config
from .printing import nprint

NOT_PY_CODE_EXTS = {
  "3dm",
  "3ds",
  "3g2",
  "3gp",
  "7z",
  "8svx",
  "DS_Store",
  "a",
  "aac",
  "ac",
  "adp",
  "aff",
  "ai",
  "aif",
  "aifc",
  "aiff",
  "aix",
  "alz",
  "am",
  "ape",
  "apk",
  "applescript",
  "ar",
  "arj",
  "as",
  "asf",
  "asm",
  "au",
  "avi",
  "bak",
  "baml",
  "bh",
  "bin",
  "bk",
  "bmp",
  "btif",
  "bz2",
  "bzip2",
  "c",
  "cab",
  "caf",
  "cat",
  "cc",
  "cdxml",
  "cfg",
  "cgm",
  "cl",
  "class",
  "cmx",
  "cnf",
  "coffee",
  "conf",
  "coverity",
  "cpio",
  "cpp",
  "cr2",
  "crt",
  "cs",
  "css",
  "css_t",
  "csv",
  "cur",
  "cxx",
  "d",
  "dart",
  "dat",
  "dcm",
  "deb",
  "dectest",
  "dex",
  "dic",
  "dict",
  "djvu",
  "dll",
  "dmg",
  "dng",
  "doc",
  "docm",
  "docx",
  "dot",
  "dotm",
  "dra",
  "dsk",
  "dsp",
  "dts",
  "dtshd",
  "dvb",
  "dwg",
  "dxf",
  "ebnf",
  "ecelp4800",
  "ecelp7470",
  "ecelp9600",
  "egg",
  "el",
  "elc",
  "eol",
  "eot",
  "epub",
  "erl",
  "es",
  "exe",
  "exr",
  "ext",
  "f",
  "f4v",
  "f90",
  "fasl",
  "fbs",
  "fh",
  "fla",
  "flac",
  "fli",
  "flv",
  "for",
  "fpx",
  "fs",
  "fsi",
  "fsscript",
  "fst",
  "fsx",
  "fvt",
  "g3",
  "gh",
  "gif",
  "go",
  "graffle",
  "gz",
  "gzip",
  "h",
  "h261",
  "h263",
  "h264",
  "hdr",
  "hdx",
  "hh",
  "hpp",
  "hrl",
  "hs",
  "html",
  "hxx",
  "i",
  "icns",
  "ico",
  "idl",
  "idx",
  "ief",
  "img",
  "ini",
  "ipa",
  "iso",
  "jar",
  "java",
  "jl",
  "jpeg",
  "jpg",
  "jpgv",
  "jpm",
  "js",
  "json",
  "jxr",
  "key",
  "kt",
  "kts",
  "ktx",
  "l",
  "latex",
  "lha",
  "lhs",
  "lib",
  "lisp",
  "litcoffee",
  "lsp",
  "lua",
  "lvp",
  "lz",
  "lzh",
  "lzma",
  "lzo",
  "m",
  "m3u",
  "m4",
  "m4a",
  "m4v",
  "mak",
  "man",
  "mar",
  "md",
  "mdi",
  "mht",
  "mid",
  "midi",
  "mj2",
  "mka",
  "mkv",
  "ml",
  "mli",
  "mm",
  "mmr",
  "mng",
  "mobi",
  "mov",
  "movie",
  "mp3",
  "mp4",
  "mp4a",
  "mpeg",
  "mpg",
  "mpga",
  "mxu",
  "nasm",
  "nb",
  "nef",
  "nib",
  "npx",
  "nsi",
  "nsis",
  "numbers",
  "nupkg",
  "nuspec",
  "o",
  "oga",
  "ogg",
  "ogv",
  "otf",
  "pack",
  "pages",
  "pbm",
  "pcx",
  "pdb",
  "pdf",
  "pea",
  "pem",
  "pgm",
  "phar",
  "php",
  "php-s",
  "php3",
  "php4",
  "php5",
  "php7",
  "phps",
  "pht",
  "phtml",
  "pic",
  "pl",
  "plist",
  "pm",
  "png",
  "pnm",
  "pod",
  "pot",
  "potm",
  "potx",
  "ppa",
  "ppam",
  "ppm",
  "pps",
  "ppsm",
  "ppsx",
  "ppt",
  "pptm",
  "pptx",
  "pro",
  "proj",
  "ps",
  "ps1",
  "ps1xml",
  "psc1",
  "psd",
  "psd1",
  "psm1",
  "pssc",
  "pya",
  "pyc",
  "pyo",
  "pyv",
  "qt",
  "r",
  "rar",
  "ras",
  "raw",
  "rb",
  "rc",
  "rda",
  "rdata",
  "rds",
  "resources",
  "rgb",
  "rip",
  "rlc",
  "rlib",
  "rmf",
  "rmvb",
  "rs",
  "rst",
  "rtf",
  "rz",
  "s",
  "s3m",
  "s7z",
  "sccd",
  "scm",
  "scpt",
  "scptd",
  "scss",
  "sgi",
  "shar",
  "sil",
  "sip",
  "sketch",
  "slk",
  "sln",
  "sml",
  "smv",
  "sndt",
  "snk",
  "so",
  "sql",
  "srl",
  "ss",
  "stl",
  "stp",
  "sub",
  "suo",
  "supp",
  "svg",
  "swf",
  "swift",
  "t",
  "tar",
  "tbc",
  "tbz",
  "tbz2",
  "tcl",
  "tex",
  "tga",
  "tgz",
  "thm",
  "thmx",
  "tif",
  "tiff",
  "tlz",
  "ttc",
  "ttf",
  "txt",
  "txz",
  "udf",
  "ui",
  "utf8",
  "uvh",
  "uvi",
  "uvm",
  "uvp",
  "uvs",
  "uvu",
  "valgrind",
  "vb",
  "vcxproj",
  "viv",
  "vob",
  "voc",
  "war",
  "wasm",
  "wat",
  "wav",
  "wax",
  "wbmp",
  "wdp",
  "weba",
  "webm",
  "webp",
  "whl",
  "wim",
  "wixproj",
  "wl",
  "wm",
  "wma",
  "wmv",
  "wmx",
  "woff",
  "woff2",
  "wpr",
  "wrm",
  "wvx",
  "wxl",
  "wxs",
  "xbm",
  "xhtml",
  "xif",
  "xla",
  "xlam",
  "xls",
  "xlsb",
  "xlsm",
  "xlsx",
  "xlt",
  "xltm",
  "xltx",
  "xm",
  "xmind",
  "xml",
  "xpi",
  "xpm",
  "xs",
  "xsl",
  "xwd",
  "xz",
  "yaml",
  "yml",
  "z",
  "zip",
  "zipx",
}

def probably_python_file(path):
  _, ext = splitext(path.lower())
  ext = ext[1:]

  # Always scan definite Python files.
  if ext in {"py", "py3", "pyw", "pyj", "pyi"}:
    return True

  # Skip all non-code Python files.
  if ext in {"pyc", "pyd", "pxd", "pyx", "pyo"} or ext in NOT_PY_CODE_EXTS:
    return False

  # Try opening file for reading as a text device.
  try:
    with open(path, mode="r", encoding="utf-8") as fp:
      for _i in range(10):
        # A script with a magic line might contain "python".
        line = fp.readline().lower().strip()
        if line.startswith("#!") and "python" in line:
          return True
  except Exception:
    # Not python if not readable text file.
    return False

  return False

# Only invoke os.lstat() once per path. Instead of twice via a call to isdir() and isfile() that
# calls os.stat() internally. Unless it is a symlink, then another os.stat() is made to check what
# is pointed to.
def stat_path(path, scan_symlink_folders=False):
  try:  # pragma: no cover
    st = lstat(path)  # Don't follow symlink.
    if not S_ISLNK(st.st_mode):
      return st

    # Ignore symlink if pointing to a dir.
    st = stat(path)  # Follow symlink.
    if S_ISDIR(st.st_mode) and not scan_symlink_folders:
      return None
    return st
  except OSError:
    return None

# Called concurrently in an iterative fashion. Each invocation will return accepted paths and a list
# of further arguments tuples, if any.
def detect_paths_incremental(args):
  (paths, depth, hidden, ignore_chars, scan_symlink_folders, config) = args
  assert config is not None
  accepted = []
  further_args = []
  for path in paths:
    try:
      if any(ic in path for ic in ignore_chars) or config.is_excluded_by_regex(path):
        continue  # pragma: no cover
      if not hidden and path != "." and path[0] == ".":
        continue
      if config.make_paths_absolute():
        path = abspath(path)

      # Scan top-level folders, or input folders, in all cases.
      st = stat_path(path, True if depth == 0 else scan_symlink_folders)
      if st is None:
        continue

      if S_ISDIR(st.st_mode):
        files = [join(path, p) for p in listdir(path) if hidden or p[0] != "."]
        further_args.append((files, depth + 1, hidden, ignore_chars, scan_symlink_folders, config))
      elif S_ISREG(st.st_mode) and (depth == 0 or probably_python_file(path)):
        accepted.append(path)
    except OSError as ex:
      nprint("Ignoring {}: {}".format(path, ex), config)
      continue
  return (accepted, further_args)

# Some detected paths might not be python code since not all files use extensions like ".py" and
# ".pyw", for instance. But try directly specified files on CLI, on depth 0, in any case (non-python
# files will be ignored when trying to parse them). Paths containing chars in `ignore_chars` will be
# ignored, as will any file excluded by regex from the config.
def detect_paths(paths, hidden=False, processes=cpu_count(), ignore_chars=None,
                 scan_symlink_folders=False, config=None):
  assert config is not None
  if isinstance(paths, str):
    paths = [paths]
  accept_paths = []
  depth = 0
  ignore_chars = ignore_chars or []
  args = [(paths, depth, hidden, ignore_chars, scan_symlink_folders, config)]

  try:
    # pylint: disable=consider-using-with
    pool = Pool(processes=processes) if processes > 1 else None

    # Automatically don't use concurrency when only one process is specified to be used.
    def act(args):
      if processes == 1:
        return [detect_paths_incremental(arg) for arg in args]  # pragma: no cover
      return pool.imap(detect_paths_incremental, args)

    while args:
      new_args = []
      for (acc, further_args) in act(args):
        if acc:
          accept_paths += acc
        if further_args:
          new_args += further_args
      args = new_args

    if pool:
      pool.close()
  except RuntimeError:
    nprint("""RuntimeError: If running `detect_paths()` outside of `if __name__ == \"__main__\":`
it, or the code calling it, must be done within it instead.""", config)
  return accept_paths

def visit(source, config=None, path=None):
  """Analyze source code and yield source code visitor instance which can be queried for further
information. A default config will be used if it isn't specified. If path is specified, it will
occur in errors instead of the default '<unknown>'.
  """
  if config is None:
    config = Config()

  parser = Parser(source, path)
  (node, mins, novermin) = parser.detect(config)
  if node is None:
    return mins

  visitor = SourceVisitor(config=config, path=path, source=source)
  visitor.set_no_lines(novermin)
  visitor.tour(node)

  # Ensure that minimum versions are calculatd such that `output_text()` invocations make sense.
  visitor.minimum_versions()

  return visitor

def detect(source, config=None, path=None):
  """Analyze and detect minimum versions from source code. A default config will be used if it isn't
  specified. If path is specified, it will occur in errors instead of the default '<unknown>'.
  """
  visitor = visit(source, config, path)
  if isinstance(visitor, SourceVisitor):
    return visitor.minimum_versions()
  return visitor


from flask import render_template
from app import app
import requests
from bs4 import BeautifulSoup

url = "http://static.cricinfo.com/rss/livescores.xml"
teams = (
    "Chennai", "Delhi",
    "Punjab", "Kolkata",
    "Mumbai", "Rajasthan",
    "Bangalore", "Hyderabad"
    )

@app.route('/')
@app.route('/index')
def index():
	r = requests.get(url)

	while r.status_code is not 200:
	        r = requests.get(url)

	soup = BeautifulSoup(r.text)
	titles = soup.find_all("title")
	size = len(titles)
	matches = []
	for match in range(size):
	    if len(set(titles[match].text.split(" ")).intersection(set(teams))) > 0:
	    	matches.append(titles[match].text)
	return '''

    <title>Live IPL Score</title>

''' + '
'.join(matches) + '''

'''


import os
import glob
import torch
from torch import nn
import gym

import pybullet_envs
import shutil
gym.logger.set_level(40)

def wrap_monitor(env):
    return gym.wrappers.Monitor(
        env, '/tmp/monitor', video_callable=lambda x: True, force=True)

def play_mp4():
    path = glob.glob(os.path.join('/tmp/monitor', '*.mp4'))[0]
    shutil.move(path, './movies/outset.mp4')

class SACActor(nn.Module):

    def __init__(self, state_shape, action_shape, std=0.0):
        super().__init__()

        self.net = nn.Sequential(
            nn.Linear(state_shape[0], 256),
            nn.ReLU(inplace=True),
            nn.Linear(256, 256),
            nn.ReLU(inplace=True),
            nn.Linear(256, 2 * action_shape[0]),
        )
        self.std = std

    def forward(self, states):
        with torch.no_grad():
            actions = torch.tanh(self.net(states).chunk(2, dim=1)[0])
            return actions.add_(torch.randn_like(actions) * self.std).clamp_(-1.0, 1.0)

    def load(self, path):
        self.load_state_dict(torch.load(path))

def run_expert(env_id, weight_path, std=0.0, device=torch.device('cuda')):
    env = wrap_monitor(gym.make(env_id))

    actor = SACActor(env.observation_space.shape, env.action_space.shape, std).to(device)
    actor.load(weight_path)

    state = env.reset()
    done = False

    while (not done):
        action = actor(torch.tensor(state, dtype=torch.float, device=device).unsqueeze_(0)).cpu().numpy()[0]
        state, _, done, _ = env.step(action)

    del env
    del actor
    play_mp4()

if __name__ == "__main__":
    run_expert(
        'HalfCheetahBulletEnv-v0',
        os.path.join('./logs/expert', 'expert.pth'),
        std=0.1
    )


#User function Template for python3

class Solution:
    def getMinDiff(self, nums, n, k):
        # code here
        if len(nums) == 1:
            return 0
        else:
            nums.sort()
            smallest = nums[0]
            largest = nums[-1]
            ans = largest - smallest
            for i in range(len(nums)-1):
                if nums[i + 1] -k < 0:
                    continue
                ans = min(ans, max(largest - k, nums[i] + k) - min(smallest + k, nums[i+1] - k ))
            return ans

#{
#  Driver Code Starts
#Initial Template for Python 3

if __name__ == '__main__':
    tc = int(input())
    while tc > 0:
        k = int(input())
        n = int(input())
        arr = list(map(int, input().strip().split()))
        ob = Solution()
        ans = ob.getMinDiff(arr, n, k)
        print(ans)
        tc -= 1

# } Driver Code Ends

Minimize the Heights II - GFG/minimize-the-heights-ii.py


def longest_subarray(arr):
    r = []
    sub = []
    i1 = 0
    i2 = 0
    while i2 < len(arr):
        x = arr[i2]
        if sub.count(x) < 2:
            sub.append(x)
            if len(set(sub)) > 2:
                sub.pop()
                if len(sub) > len(r):
                    r = sub
                i1 += 1
                sub = arr[i1:i2+1]
            elif len(sub) == 4:
                i1 += 1
                if len(sub) > len(r):
                    r = sub
                elif len(sub) == len(r):
                    if sum(sub) > sum(r):
                        r = sub
                sub = arr[i1:i2+1]
        else:
            i1 += 1
            sub = arr[i1:i2 + 1]
        i2 += 1
    if len(sub) > len(r):
        r = sub
    return r

if __name__ == "__main__":
    assert longest_subarray([0, 1, 2, 1, 2, 3]) == [1, 2, 1, 2]
    assert longest_subarray([1, 1, 1, 3, 3, 2, 2]) == [3, 3, 2, 2]
    assert longest_subarray([3, 2, 2, 1]) == [3, 2, 2]
    assert longest_subarray([2, 2, 1]) == [2, 2, 1]


import random

def print_board(data):
    print("-------------")
    print(" %c : %c : %c " % (data[0], data[1], data[2]))
    print(" %c : %c : %c " % (data[3], data[4], data[5]))
    print(" %c : %c : %c " % (data[6], data[7], data[8]))
    print("-------------")

def choose_pattern():
    side = input("패턴 입력[X/O]")
    while side != 'X' and side != 'O':
        print('wrong input')
        side = input("패턴 입력[X/O]")
    if side is 'X':
        n_side = 'O'
    else:
        n_side = 'X'
    return [side] + [n_side]

def restart():
    again = input('replay? [Y/N]')
    if again is 'N':
        return 1
    else:
        return 0

def result(win, lose, draw):
    print("Win:%d   Lose:%d   Draw:%d   Ratio: %2d %%" % (win, lose, draw, 100 * win / (win + lose + draw)))

def valid(n):
    if len(n) != 1 or (ord(n) < ord('1') or ord(n) > ord('9')):
        return 1

def repeated(n, stat):
    if stat[int(n) - 1] != ' ':
        return 1

def pick(stat):
    p = input("your turn")
    while valid(p) or repeated(p, stat):
        print("wrong input")
        if valid(p):
            p = input("wrong input")
        elif repeated(p, stat):
            print("wrong input")
            p = input()
    return p

lines = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]]
win = 0
lose = 0
draw = 0

def computer_turn(stat):
    win = []
    lose = []
    for i in lines:
        line = []
        for t in range(3):
            line.append(i[t])
        p_cnt = []
        cnt = []
        for t in range(3):
            if stat[i[t]] is Player:
                p_cnt.append(i[t])
                line.remove(i[t])
            elif stat[i[t]] is Computer:
                cnt.append(i[t])
                line.remove(i[t])
        if len(cnt) + len(p_cnt) is 3:
            continue
        if len(cnt) is 2 and len(p_cnt) is 0:
            win.append(line[0])
        if len(cnt) is 0 and len(p_cnt) is 2:
            lose.append(line[0])
    if len(win):
        return win[0]
    if len(lose):
        return lose[0]
    empty = []
    for i in range(9):
        if stat[i] is ' ':
            empty.append(i)
    random.shuffle(empty)
    return empty[0]

def check(stat, num, player, computer):
    global win, lose, draw
    for i in lines:
        if stat[i[0]] == stat[i[1]] == stat[i[2]]:
            if stat[i[0]] is ' ':
                continue
            if stat[i[0]] is player:
                print("이겼습니다")
                win += 1
                return 1

            elif stat[i[0]] is computer:
                print("졌습니다")
                lose += 1
                return 1
    if num is 9:
        print("비겼습니다")
        draw += 1
        return 1
    return 0

print("""Tic Tac Toe 게임을 시작합니다!

게임은 3*3 격자판에서 진행됩니다.
당신은 컴퓨터와 번갈아가며 게임을 하게 됩니다.
선공과 후공은 랜덤으로 결정됩니다.
가로, 세로 대각선으로 같은 표시(O/X)가 놓인다면, 해당 표시의 플레이어가 승리합니다!

Game Start!
""")

ingame = 1
while ingame is 1:
    Player, Computer = choose_pattern()
    print("선공/후공을 정합니다")
    first = random.randint(0, 1)

    if first is 1:
        print("player first")
    else:
        print("computer first")
    game = 1
    status = [' '] * 9
    while game <= 9:
        if first is 1:
            status[int(pick(status)) - 1] = Player
            print_board(status)
            if check(status, game, Player, Computer):
                if restart():
                    ingame = 0
                break
            game += 1

        status[int(computer_turn(status))] = Computer
        print_board(status)
        if check(status, game, Player, Computer):
            if restart():
                ingame = 0
            break
        game += 1
        first = 1

result(win, lose, draw)


# loosely adapted from a combination of https://towardsdatascience.com/nlp-part-3-exploratory-data-analysis-of-text-data-1caa8ab3f79d
# and https://towardsdatascience.com/preprocessing-text-data-using-python-576206753c28

import csv
from nicknames import *

name_list = [x.lower() for x in name_list]

import nltk
from nltk.tokenize import word_tokenize
from nltk.tag import pos_tag
from nltk.stem import WordNetLemmatizer
from nltk.corpus import stopwords, wordnet
from nltk import classify
from nltk import NaiveBayesClassifier

import random

import pandas as pd
import numpy as np
import string
import contractions

from functools import reduce

import matplotlib.pyplot as plt

is_wolf = {} #(profile_id, game#)
is_human = {} #(profile_id, game#)
wolfposts = []
humanposts=[]
otherposts=[]
gms = [0]*50

with open('Players by role and death.csv', newline='') as csvfile:
    inforeader = csv.reader(csvfile, delimiter=',',quotechar="\"")
    for row in inforeader:
        if row[2] != '':
            if name_find(row[1])[-1] == '?':
                print(row[0], row[1])
            is_wolf[(name_lookup[name_find(row[1].lower()).lower()], row[0])] = row[5]
            is_human[(name_lookup[name_find(row[1].lower()).lower()], row[0])] = row[4]

def wolf(name, game): #just for flexibility
    name = str(name)
    game = str(game)
    name = name.lower()
    if name in names.keys():
        profile = name
    elif name in name_lookup.keys():
        profile = name_lookup[name]
    else:
        profile = name_lookup[name_find(name)]
    try:
        result = bool(int(is_wolf[(profile, game)]))
        return result
    except KeyError:
        if gms[int(game)] == 0: #since the posts are in order, this should be the initial post by the GM
            gms[int(game)] = profile
        return False #not in the game, or a GM post

def human(name, game): #note that this is not just the opposite of wolf(name, game), because there are 3rd parties and team-switchers who are considered neither
    game = str(game)
    name = str(name)
    name = name.lower()
    if name in names.keys():
        profile = name
    elif name in name_lookup.keys():
        profile = name_lookup[name]
    else:
        profile = name_lookup[name_find(name)]
    try:
        result = bool(int(is_human[(profile, game)]))
        return result
    except KeyError: #people who aren't in the game aren't wolves or human (might be GM, but that's set by Wolf)
        return False

def standardize_name(word):
    if word.lower() in name_list: #don't want to use name_find here, because it will have all kinds of false positives, I'd rather miss some less standard nicknames
        return(names[name_lookup[word.lower()]][0])
    else:
        return word

with open('post_archive.csv') as file:
    df = pd.read_csv(file, delimiter=',', quotechar="\'")
file.close()

#columns: ['post_id', 'post_text', 'profile_id', 'game', 'page']
df.drop('page', axis=1, inplace=True)

df['wolf'] = df.apply(lambda row: int(wolf(row['profile_id'], row['game'])), axis=1)
df['human'] = df.apply(lambda row: int(human(row['profile_id'], row['game'])), axis=1)
#df['usable'] = df.apply(lambda row: (int(row['human']) or int(row['wolf'])), axis=1)

df = df[(df['human']==1) | (df['wolf']==1)] #eliminate GM posts, outside players, 3rd parties
df.drop('human', axis=1, inplace=True)

def fix_names(pair):
    name, tag = pair
    if name in name_list:
        tag = 'NNP' #code for a proper noun, in case I ever use these directly
    return((name, tag))

def replace_names(pair):
    name, tag = pair
    if name in name_list:
        name = 'ForumName'
        tag = 'NNP'
    return((name, tag))

def convert_pos(tag):
    if tag.startswith('J'):
        return wordnet.ADJ
    elif tag.startswith('V'):
        return wordnet.VERB
    elif tag.startswith('N'):
        return wordnet.NOUN
    elif tag.startswith('R'):
        return wordnet.ADV
    else:
        return wordnet.NOUN

def token_dicts(tokens_list):
    for tokens in tokens_list:
        yield dict([token, True] for token in tokens)

def process_posts(post_iter): #should work on any iterator, confirmed to work on df columns, lists, filters, and maps
    ws = pd.DataFrame({'post_text':post_iter})
    ws['no_contractions'] = ws['post_text'].apply(lambda x: [contractions.fix(word) for word in str(x).split()])
    ws['new_post'] = [' '.join(map(str, l)) for l in ws['no_contractions']]
    ws['tokenized'] = ws['new_post'].apply(word_tokenize)
    ws['standardized_names'] = ws['tokenized'].apply(lambda x: [standardize_name(word) for word in x])
    ws['lower'] = ws['standardized_names'].apply(lambda x: [word.lower() for word in x])
    ws['no_punctuation'] = ws['lower'].apply(lambda x: [word for word in x if word not in string.punctuation])
    stop_words = set(stopwords.words('english'))
    ws['no_stopwords'] = ws['no_punctuation'].apply(lambda x: [word for word in x if word not in stop_words])
    ws['pos_tags'] = ws['no_stopwords'].apply(nltk.tag.pos_tag) #'pos' stands for 'part of speech'
    # ^this^ wasn't catching proper nouns on forum names, which I can fix
    # this isn't perfect, because the tagger isn't taking into account that these are nouns as it goes through the sentence
    # but it's the best I can do without rewriting the tagger
    #ws['fixed_names'] = ws['pos_tags'].apply(lambda x: [fix_names(pair) for pair in x])
    ws['fixed_names'] = ws['pos_tags'].apply(lambda x: [replace_names(pair) for pair in x])
    ws['wordnet_pos'] = ws['fixed_names'].apply(lambda x: [(word, convert_pos(pos_tag)) for (word, pos_tag) in x])
    ws['lemmatized'] = ws['wordnet_pos'].apply(lambda x: [WordNetLemmatizer().lemmatize(word, tag) for word, tag in x])
    return ws['lemmatized']

df['lemmatized'] = process_posts(df['post_text'])

# train for the nth game, i.e. with the first (n-1) games
# training for 47 is about an 80/20 split
train_for = 47
train_cutoff = list(df['game']).index(train_for)

wolf_tokens = token_dicts(df[(df['wolf']==1) & (df['game'] < train_for)]['lemmatized'])
human_tokens = token_dicts(df[(df['wolf']==0) & (df['game'] < train_for)]['lemmatized'])

wolf_dataset = [(token_dict, "wolf") for token_dict in wolf_tokens]
human_dataset = [(token_dict, "human") for token_dict in human_tokens]

dataset = wolf_dataset + human_dataset
random.shuffle(dataset)

#cutoff = int(len(dataset)*.8)
#train_data = dataset[:cutoff]
#test_data = dataset[cutoff:]
#shortclassifier = NaiveBayesClassifier.train(train_data)
#print("Accuracy is:", classify.accuracy(shortclassifier, test_data))
#print(shortclassifier.show_most_informative_features(20))

shortclassifier = NaiveBayesClassifier.train(dataset)
#print("Accuracy is:", classify.accuracy(shortclassifier, test_data)

test_df = df[(df['game'] >= train_for)]
grouped = test_df.groupby(['profile_id', 'game'])
grouped_l = [g[1] for g in grouped]

results=[]
for g in grouped_l:
    temp_tokens = token_dicts(g['lemmatized'])
    if max(g['wolf']) == 0:
        label="human"
    elif min(g['wolf']) == 1:
        label="wolf"
    temp_data = [(token_dict, label) for token_dict in temp_tokens]
    results.append(classify.accuracy(shortclassifier, temp_data))
    #print("Accuracy for", g, "is:", results[-1])
#print(results)
#use classifier.classify() to clarify which/how many posts are wolfy

# Notes:
# Accuracy ~64-68% depending on the train/test split
# random guessing according to the probability of wolves gives 61.25% accuracy
# naively guessing all-human gives 75% accuracy

# there are also several oddities cropping up in the top 20 features:
# names, random words that only came up in one game, etc.
# So maybe cleaning up some noise would help

# I suspect some of this is that even wolves have some human-seeming posts
# I want to explore two strategies: what % of a user's posts in a game seem wolfy?

# Compiling all posts into one (by user and game), classifying based on that:
"""
grouped = df.groupby(['profile_id', 'game'])

l = [g[1] for g in grouped]
#combine posts into one per person per game, keep the wolf column, drop everything else
#join would have been more elegant, but it messed up my escape characters

l = [[reduce(lambda x, y: str(x) + '. ' + str(y), x['post_text']), int(x['wolf'].mean())] for x in l]
megaposts = pd.DataFrame(l, columns=['megaposts', 'wolf'])

megaposts['lemmatized'] = process_posts(megaposts['megaposts'])

wolf_mega_tokens = token_dicts(megaposts[(megaposts['wolf']==1)]['lemmatized'])
human_mega_tokens = token_dicts(megaposts[(megaposts['wolf']==0)]['lemmatized'])

wolf_megaset = [(token_dict, "wolf") for token_dict in wolf_mega_tokens]
human_megaset = [(token_dict, "human") for token_dict in human_mega_tokens]

megaset = wolf_megaset + human_megaset
random.shuffle(megaset)

megacutoff = int(len(megaset)*.8)
train_mega = megaset[:megacutoff]
test_mega = megaset[megacutoff:]

megaclassifier = NaiveBayesClassifier.train(train_mega)

print("Accuracy is:", classify.accuracy(megaclassifier, test_mega))
print(megaclassifier.show_most_informative_features(20))
"""
# This is way worse, ~25-35% accurate
# I think the classifier only uses presence rather than frequency
# So the bigger chunks don't work as well because they lose more frequency info

#prospective addition:
df['td'] = df['lemmatized'].apply(lambda x: dict([token, True] for token in x))
#note: maybe don't assume there's a wolf column? or have one version for training and another for testing
df['label']=df.apply(lambda row: 'wolf'*row['wolf'] + 'human'*(1-row['wolf']), axis=1)
df['tdl'] = df.apply(lambda row: (row['td'], row['label']), axis=1)
#for testing:
df['predicted']=df['td'].apply(shortclassifier.classify)
df['wolf_prob'] = df['td'].apply(lambda x: shortclassifier.prob_classify(x).prob('wolf'))

#work in progress
words = reduce(lambda x, y: list(set(x+y)), df['lemmatized'])[:3000]
rf = pd.DataFrame()
for w in words:
    print(w, words.index(w))
    rf[w] = df['td'].apply(lambda x: int(w in x.keys()))
X_train = rf.iloc[:train_cutoff,:]
X_test = rf.iloc[train_cutoff:,:]
y_train = df.iloc[:train_cutoff,:]['wolf']
y_test = df.iloc[train_cutoff:,:]['wolf']

from sklearn.ensemble import RandomForestRegressor

model = RandomForestRegressor()
model.fit(X_train, y_train)
print(model.score(X_test, y_test)) #note, this is R squared, not accuracy

# Accuracy is terrible, my shell crashes if I use more than 1/5 of the words
# and printing to test/improve speed revealed many punctuation issues

# I think the previous approach is better and more manageable

#non-training data only
wolf_probs = df[(df['wolf']==1) & (df['game'] >= train_for)]['wolf_prob']
human_probs = df[(df['wolf']==0) & (df['game'] >= train_for)]['wolf_prob']

#plt.hist(human_probs, bins=25)
#plt.hist(wolf_probs, bins=25)


#!/usr/bin/python3

import sys
import os
import matplotlib
import matplotlib.pyplot as plt
import numpy as np

def find_columns(headers):
	"""
	This function accepts the header line of the score file as input, and will return a dictionary that assocaites header/column names with their repsecitve indices
	This is to help make the code more abstract and prevent future issues/hardcoding
	"""

	index_store = {}

	# Split the header line of the file by white space... iterate through each header, and store the name and index in the dictionary
	for header, i in zip(headers.split(),range(len(headers.split()))):
		index_store[header]=i

	# return this dictionary
	return index_store

def read_score_file(score_file):

	try:
		with open(score_file,'r') as f:
			contents = f.readlines()
	except:
		print('Error reading file {}... are you in the right directory?'.format(score_file))
		sys.exit(1)

	index_store = find_columns(contents[1]) # pass in header line and recieve index dictionary

	# initialize the sum and count to get average
	scores = []
	sum_score = 0
	cnt = 0

	for line in contents[2:]: # Iterate through all but first two lines of the score file
		line = line.split()
		scores.append(float(line[index_store['I_sc']]))
		cnt += 1

	scores.sort() # sort the scores

	return np.average(scores[:2]) # return average of top 3 docks

if __name__ == "__main__":

	root = './docking/'

	sub_dirs = [x[1] for x in os.walk(root)]
	sub_dirs = sorted(sub_dirs[0])

	print('Found the following loop directories:')
	for sub in sub_dirs:
		print(sub)

	docking_avgs_6_25 = []
	docking_avgs_7_50 = []

	#Analyze docks for pH=6.25
	for folder in sub_dirs:
		try:
			avg_6_25 = read_score_file(root + folder + '/6.25/output_files/score_local_dock.sc')
			docking_avgs_6_25.append(avg_6_25)

			avg_7_50 = read_score_file(root + folder + '/7.50/output_files/score_local_dock.sc')
			docking_avgs_7_50.append(avg_7_50)

		except:
			print('Error reached while reading file... Skipping to next')
			continue

	# for avg in docking_avgs:
	# 	print(avg)
	binwidth = 2
	bins = range(-30, 0 + binwidth, binwidth)

	dist_avg_6 = np.average(docking_avgs_6_25)
	dist_med_6 = np.median(docking_avgs_6_25)
	dist_std_6 = np.std(docking_avgs_6_25)

	dist_avg_7 = np.average(docking_avgs_7_50)
	dist_med_7 = np.median(docking_avgs_7_50)
	dist_std_7 = np.std(docking_avgs_7_50)

	print('\npH=6.25 | Descriptive Statistics:')
	print('-='*30)
	print('Average:\t',dist_avg_6)
	print('Median:\t\t',dist_med_6)
	print('Std:\t\t',dist_std_6)

	print('\npH=7.50 | Descriptive Statistics:')
	print('-='*30)
	print('Average:\t',dist_avg_7)
	print('Median:\t\t',dist_med_7)
	print('Std:\t\t',dist_std_7)

	# plt.hist(docking_avgs, bins=bins)
	# plt.ylabel('Frequency (cnt)')
	# plt.xlabel('Docking Interface Score (REU)')
	# plt.title('Distribution of Interface Energies Between Fc and FcRn Proteins (n={})'.format(len(docking_avgs)))
	# plt.show()