from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score
from catboost import CatBoostRegressor
import optuna

def objective(trial):
    X_train, X_test, y_train, y_test = train_test_split(train_x, train_y, test_size=0.2)
    param = {
        "loss_function": trial.suggest_categorical("loss_function", ["RMSE", "MAE"]),
        "learning_rate": trial.suggest_loguniform("learning_rate", 1e-5, 1),
        "l2_leaf_reg": trial.suggest_loguniform("l2_leaf_reg", 1e-2, 1),
        # "colsample_bylevel": trial.suggest_float("colsample_bylevel", 0.01, 1),
        "depth": trial.suggest_int("depth", 1, 16),
        "boosting_type": trial.suggest_categorical("boosting_type", ["Ordered", "Plain"]),
        "bootstrap_type": trial.suggest_categorical("bootstrap_type", ["Bayesian", "Bernoulli", "MVS"]),
        "min_data_in_leaf": trial.suggest_int("min_data_in_leaf", 2, 20),
        "one_hot_max_size": trial.suggest_int("one_hot_max_size", 2, 20),
        "iterations": trial.suggest_int("iterations", 500, 5000),
        "random_strength": trial.suggest_float("random_strength", 0.1, 50),
        "rsm": trial.suggest_float("rsm", 0, 1),
        # "bagging_temperature": trial.suggest_float("bagging_temperature", 0, 1)
    }
    # Conditional Hyper-Parameters
    if param["bootstrap_type"] == "Bayesian":
        param["bagging_temperature"] = trial.suggest_float("bagging_temperature", 0, 10)
    elif param["bootstrap_type"] == "Bernoulli":
        param["subsample"] = trial.suggest_float("subsample", 0.1, 1)

    reg = CatBoostRegressor(**param)
    reg.fit(X_train, y_train, eval_set=[(X_test, y_test)], verbose=0, early_stopping_rounds=100)
    y_pred = reg.predict(X_test)
    score = r2_score(y_test, y_pred)
    return score

from sklearn.utils import resample
from sklearn.model_selection import train_test_split
import pandas as pd
from optuna.samplers import TPESampler

train = pd.read_csv("./ml.csv")
df_majority = train[train.label == 0]
df_minority = train[train.label == 1]

df_minority_upsampled = resample(df_minority,
                                 replace=True,     # sample with replacement
                                 n_samples=39325,    # to match majority class
                                 random_state=123)
df_upsampled = pd.concat([df_majority, df_minority_upsampled])
train_x = df_upsampled.drop('label', axis=1)     # 删除表中的某一行或者某一列
train_y = df_upsampled['label']
Xy = train_test_split(train_x, train_y, test_size=0.2)
train_data, test_data, train_labels, test_labels = Xy
from sklearn.metrics import roc_auc_score, accuracy_score, f1_score, precision_score, recall_score
# reg = CatBoostRegressor(**param)
# y_pred = reg.predict(test_data)
# print('AUC→',roc_auc_score(test_labels, y_pred))
# print('ACC→',accuracy_score(test_labels, y_pred))
# print('F1 score→',f1_score(test_labels, y_pred))
# print('precision→',precision_score(test_labels, y_pred))
# print('recall→',recall_score(test_labels, y_pred))

study = optuna.create_study(sampler=TPESampler(), direction="maximize")
study.optimize(objective, n_trials=100)  # Run for 10 minutes，timeout=600
print("Number of completed trials: {}".format(len(study.trials)))
print("Best trial:")
trial = study.best_trial

print("\tBest Score: {}".format(trial.value))
print("\tBest Params: ")
for key, value in trial.params.items():
    print("    {}: {}".format(key, value))

comparison of DL and ML/catboost/catbooost用optuna调参.py


# -*- coding: utf-8 -*-
"""
Created on Tue Apr 23 02:21:00 2019

@author: djakd
"""

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import re# permet de faire des recherches très précises dans une chaîne de caractère
import time
import datetime
import random
# NOTE: this example requires PyAudio because it uses the Microphone class
import speech_recognition as sr #librairie de reconnaisssance vocal
import subprocess
import speak # permet de faire resortire la voix

# text to speek function
#def execute_command(str):
#	""" For openning eSpeak module"""
#	subprocess.Popen(['C:\Program Files (x86)\eSpeak\command_line\espeak.exe', str])

# configuration
my_Name = "patrick"
tl= 2 # for little sentences
tL= 5 # for long sentences
t = tl # default configuration
r = sr.Recognizer()
lang ="fr-FR"
recherche_direction=False

# answer function
def answer(toSay, t_stop=tl):
	"""" print and say the 'toSay' variable and can modify time pause"""
	print(toSay)
	#execute_command(toSay)
	global t
	t=t_stop

# start to discuss
discuss = True
with sr.Microphone(sample_rate = 32000) as source:
	while (discuss == True):

		# obtain audio from the microphone
		print("...") # to show he wait something from you
		audio = r.listen(source, 4, 6) # slowwwww
		print("..")	# to show he has recorded your demande

		#recuperer de l'enregistrement audio et reconnaissance vocal grace au package de google

		try:
			message = r.recognize_google(audio, language = "fr-FR")
			#print("Vous : " + message )
			del audio# permet de supprimer le message enregistré à chaque fois pour attendre le message suivant
		except sr.UnknownValueError:
			print("Je n'ai pas compris, pouvez-vous répéter ?")
			message = ""
			misUnderstood = True
		except sr.RequestError as e:
			print("Could not request results from Microsoft Bing Voice Recognition service; {0}".format(e))
			message =""
		# search if the answer exists
		if(re.search("accueil merci", message)):
			answer("acceuil ok")
			navigator="accueil"
			recherche_direction=False
		elif(re.search("activité merci",message) or re.search("programme des études",message)):
			answer("ok")
			navigator="activité"
			recherche_direction=False
		elif(re.search("direction merci", message)):
			answer("direction ok")
			navigator="direction"
			recherche_direction=True
		elif(re.search("auditoire 25 merci",message) or re.search("25 merci",message) and recherche_direction==True):
			#answer("ok 25")
			direction="comme indiquez sur le plan, prenez à votre gauche ensuite montez jusqu'au deuxième étage l'auditoire est face à vous légèrement à droite"
			navigator="auditoire 25"
			speak.tts(direction, lang)
		elif(re.search("auditoire 11 merci",message) or re.search("11 merci",message) and recherche_direction==True):
			#answer("ok 11")
			direction="prenez à votre droite ensuite montez jusqu'au premier étage, l'auditoire est sur votre gauche"
			navigator="auditoire 11"
			speak.tts(direction, lang)
		elif(re.search("auditoire 12 merci",message) or re.search("12 merci",message) and recherche_direction==True):
			#answer("ok 12")
			direction="prenez à votre droite ensuite montez jusqu'au premier étage puis tournez à droite, vous êtes arrivez"
			navigator="auditoire 12"
			speak.tts(direction, lang)
		elif(re.search("auditoire 23 merci",message) or re.search("23 merci",message) and recherche_direction==True):
			#answer("ok 23")
			direction="Prenez à votre droite jusqu'à l'escalier, montez jusqu'au deuxième étage puis faite quelques pas sur votre gauche l'auditoire se trouve à droite"
			navigator="auditoire 23"
			speak.tts(direction, lang)
		elif(re.search("c'est gentil", message) or re.search("merci miroir", message)):
			direction="non, ne me remerciez pas"
			speak.tts(direction, lang)
			navigator="accueil"
			discuss = False
		elif(re.search("auditoire 04 merci",message) or re.search("réfectoire merci",message) and recherche_direction==True):
			#answer("ok 05")
			direction="comme indiquer sur le plan prenez à votre droite jusqu'au IGLAB puis tournez à droite, la destination est à votre droite"
			speak.tts(direction, lang)
		elif(re.search("hall d'entrer merci",message) or re.search("secrétariat des étudiants merci",message)and recherche_direction==True):

			navigator="auditoire 23"
			speak.tts("vous y êtes",lang)

		else:
			if(misUnderstood==True):
				misUnderstood=False
			else:
				t=0

		# to avoid him listening to himself
		time.sleep(t) # stop execution
		t=tl # reset stop time

os.system("pause")


import os

from pyltp import SentenceSplitter
from pyltp import Segmentor
from pyltp import Postagger
from pyltp import NamedEntityRecognizer
import jieba

LTP_DATA_DIR = "D:\\Anaconda\\Lib\\site-packages\\ltp\\3.4"
text = "元芳你怎么看？我就趴窗口上看呗！"

def split(text):
    return SentenceSplitter.split(text)

def cut(sentences):
    return jieba.cut(sentences)

def segment(sentences):
    cws_model_path = os.path.join(LTP_DATA_DIR, "cws.model")
    lexicon_path = os.path.join(LTP_DATA_DIR, "lexicon.txt")

    segmentor = Segmentor()
    # segmentor.load(cws_model_path)
    segmentor.load_with_lexicon(cws_model_path, lexicon_path)
    words = segmentor.segment(sentences)
    segmentor.release()
    return words

def pos(words):
    pos_model_path = os.path.join(LTP_DATA_DIR, "pos.model")

    postagger = Postagger()
    postagger.load(pos_model_path)
    postags = postagger.postag(words)
    postagger.release()
    return postags

def ner(words, postags):
    ner_model_path = os.path.join(LTP_DATA_DIR, "ner.model")

    recognizer = NamedEntityRecognizer()
    recognizer.load(ner_model_path)
    netags = recognizer.recognize(words, postags)
    recognizer.release()
    return netags

def match(tokens, tag, tags, word, namedentity):
    if tokens[0] == "B":
        tags += [tag]
        namedentity += [word]
    elif tokens[0] == "I":
        tags += [tag]
        namedentity += [word]
    elif tokens[0] == "E":
        tags += [tag, " "]
        namedentity += [word, " "]
    else:
        tags += [tag, " "]
        namedentity += [word, " "]
    return tags, namedentity

def recognize(words, netags):
    namedentity = []
    tags = []
    for word, tag in zip(words, netags):
        if tag != "O":
            tokens = tag.split("-")
            if tokens[1] == "Nh":
                tags, namedentity = match(tokens, tag, tags, word, namedentity)
            elif tokens[1] == "Ni":
                tags, namedentity = match(tokens, tag, tags, word, namedentity)
            else:
                tags, namedentity = match(tokens, tag, tags, word, namedentity)

    namedentity = "".join(namedentity).split()
    tags = [tag.split("-")[-1] for tag in "".join(tags).split()]
    return dict(zip(namedentity, tags))


import json
import random
"""
变量的类型注解
"""

# 基础数据类型注解
var_1: int = 10
var_2: float = 12.32
var_3: bool = True
Var_4: str = 'Annie'

# 类对象类型注解
class Student:
    pass

stu: Student = Student()

# 基础容器类型注解
my_list: list = [1,2,3]
my_tuple: tuple = (1,2,3)
my_dict: dict = {"Annie", 23}

# 容器类型详细注解
my_list: list[int] = [1,2,3]
my_tuple: tuple[int,str,bool,float] = (1,'Annie',True,4.23) # 每个元素都要注解类型
my_dict: dict[str,int] = {"Annie", 23}

# 在注释中进行类型注解
var_4 = random.randint(1,10) # type: int
print(var_4)
var_5 = json.loads('{"name": "Annie","age": 23}') # type: dict[str,str]
print(var_5)

def func():
    return 10
#对函数返回值做注释类型注解
var_6 = func() # type: int

# 类型注解的限制
var_7: int = 'petter'
var_8: str = 123
# 以上代码可运行，类型注解只是给开发者提示用，不是强制。哪怕标记错了，也不会影响程序运行


import numpy as np
import scipy.io as sio
import pytest

from scanning_drift_corr.SPmerge01linear import SPmerge01linear, _get_linear_drift
from scanning_drift_corr.sMerge import sMerge
from scanning_drift_corr.tools import _hanning_weight

def test_no_provided_image():
    scanAngles = (30, 120)
    sm = SPmerge01linear(scanAngles)

    assert sm is None

def test_result_small_delta(small_delta_matrix):
    im1, im2 = small_delta_matrix
    scanAngles = (0, 90)

    sm = SPmerge01linear(scanAngles, im1, im2)
    imgtrans0 = sm.imageTransform[0, ...]
    imgtrans1 = sm.imageTransform[1, ...]
    imgden0 = sm.imageDensity[0, ...]
    imgden1 = sm.imageDensity[1, ...]
    scanOr = sm.scanOr

    mstruct = sio.loadmat('matlab_result/SPmerge01linear_result_small_delta.mat')
    imgtrans0_m = mstruct['it1']
    imgtrans1_m = mstruct['it2']
    imgden0_m = mstruct['id1']
    imgden1_m = mstruct['id2']
    scanOr_m = mstruct['scOr'].T - 1

    assert np.isclose(imgtrans0, imgtrans0_m).all()
    assert np.isclose(imgtrans1, imgtrans1_m).all()
    assert np.isclose(imgden0, imgden0_m).all()
    assert np.isclose(imgden1, imgden1_m).all()
    assert np.isclose(scanOr, scanOr_m).all()

def test_result_small_delta_stack(small_delta_matrix_stack):
    stack = small_delta_matrix_stack
    scanAngles = (0, 90)

    sm = SPmerge01linear(scanAngles, stack)
    imgtrans0 = sm.imageTransform[0, ...]
    imgtrans1 = sm.imageTransform[1, ...]
    imgden0 = sm.imageDensity[0, ...]
    imgden1 = sm.imageDensity[1, ...]
    scanOr = sm.scanOr

    mstruct = sio.loadmat('matlab_result/SPmerge01linear_result_small_delta.mat')
    imgtrans0_m = mstruct['it1']
    imgtrans1_m = mstruct['it2']
    imgden0_m = mstruct['id1']
    imgden1_m = mstruct['id2']
    scanOr_m = mstruct['scOr'].T - 1

    assert np.isclose(imgtrans0, imgtrans0_m).all()
    assert np.isclose(imgtrans1, imgtrans1_m).all()
    assert np.isclose(imgden0, imgden0_m).all()
    assert np.isclose(imgden1, imgden1_m).all()
    assert np.isclose(scanOr, scanOr_m).all()

@pytest.mark.parametrize('angles, mfile',
                         [((45, 135), 'SPmerge01linear_result_45_135_simulated_data.mat'),
                          ((1, 91), 'SPmerge01linear_result_1_91_simulated_data.mat'),
                          ((0, 90), 'SPmerge01linear_result_0_90_simulated_data.mat'),
                          ((-90, -180), 'SPmerge01linear_result_m90_m180_simulated_data.mat'),
                          ])
def test_result_ignore_edge_simulated_data(angles, mfile, MATLAB_simulated_images):

    im1, im2 = MATLAB_simulated_images
    scanAngles = angles
    bd = int(0.25*im1.shape[0]) # the start and end indices for comparison

    sm = SPmerge01linear(scanAngles, im1, im2)
    imgtrans0 = sm.imageTransform[0, ...]
    imgtrans1 = sm.imageTransform[1, ...]
    imgden0 = sm.imageDensity[0, ...]
    imgden1 = sm.imageDensity[1, ...]
    scanOr = sm.scanOr

    mstruct = sio.loadmat('matlab_result/'+mfile)
    imgtrans0_m = mstruct['it1']
    imgtrans1_m = mstruct['it2']
    imgden0_m = mstruct['id1']
    imgden1_m = mstruct['id2']
    scanOr_m = mstruct['scOr'].T - 1

    assert np.isclose(imgtrans0[bd:-bd, bd:-bd], imgtrans0_m[bd:-bd, bd:-bd]).all()
    assert np.isclose(imgtrans1[bd:-bd, bd:-bd], imgtrans1_m[bd:-bd, bd:-bd]).all()
    assert np.isclose(imgden0[bd:-bd, bd:-bd], imgden0_m[bd:-bd, bd:-bd]).all()
    assert np.isclose(imgden1[bd:-bd, bd:-bd], imgden1_m[bd:-bd, bd:-bd]).all()
    assert np.isclose(scanOr, scanOr_m).all()

def test_result_ignore_edge_4_images_simulated_data(MATLAB_simulated_images):

    im1, im2 = MATLAB_simulated_images
    scanAngles = (0, 90, 45, 135)
    bd = int(0.25*im1.shape[0]) # the start and end indices for comparison

    sm = SPmerge01linear(scanAngles, im1, im2, im1, im2, parallel=False)
    imgtrans0 = sm.imageTransform[0, ...]
    imgtrans1 = sm.imageTransform[1, ...]
    imgtrans2 = sm.imageTransform[2, ...]
    imgtrans3 = sm.imageTransform[3, ...]
    imgden0 = sm.imageDensity[0, ...]
    imgden1 = sm.imageDensity[1, ...]
    imgden2 = sm.imageDensity[2, ...]
    imgden3 = sm.imageDensity[3, ...]
    scanOr = sm.scanOr

    mstruct = sio.loadmat('matlab_result/'+'SPmerge01linear_result_0_90_45_135_simulated_data.mat')
    imgtrans0_m = mstruct['it1']
    imgtrans1_m = mstruct['it2']
    imgtrans2_m = mstruct['it3']
    imgtrans3_m = mstruct['it4']
    imgden0_m = mstruct['id1']
    imgden1_m = mstruct['id2']
    imgden2_m = mstruct['id3']
    imgden3_m = mstruct['id4']
    scanOr_m = mstruct['scOr'].T - 1

    assert np.isclose(imgtrans0[bd:-bd, bd:-bd], imgtrans0_m[bd:-bd, bd:-bd]).all()
    assert np.isclose(imgtrans1[bd:-bd, bd:-bd], imgtrans1_m[bd:-bd, bd:-bd]).all()
    assert np.isclose(imgtrans2[bd:-bd, bd:-bd], imgtrans2_m[bd:-bd, bd:-bd]).all()
    assert np.isclose(imgtrans3[bd:-bd, bd:-bd], imgtrans3_m[bd:-bd, bd:-bd]).all()
    assert np.isclose(imgden0[bd:-bd, bd:-bd], imgden0_m[bd:-bd, bd:-bd]).all()
    assert np.isclose(imgden1[bd:-bd, bd:-bd], imgden1_m[bd:-bd, bd:-bd]).all()
    assert np.isclose(imgden2[bd:-bd, bd:-bd], imgden2_m[bd:-bd, bd:-bd]).all()
    assert np.isclose(imgden3[bd:-bd, bd:-bd], imgden3_m[bd:-bd, bd:-bd]).all()
    assert np.isclose(scanOr, scanOr_m).all()

def test_result_small_delta_rectangle(small_delta_rectangle):
    im1, im2 = small_delta_rectangle
    scanAngles = (10, 100)

    sm = SPmerge01linear(scanAngles, im1, im2)
    imgtrans0 = sm.imageTransform[0, ...]
    imgtrans1 = sm.imageTransform[1, ...]
    imgden0 = sm.imageDensity[0, ...]
    imgden1 = sm.imageDensity[1, ...]
    scanOr = sm.scanOr

    mstruct = sio.loadmat('matlab_result/SPmerge01linear_result_small_delta_rectangle.mat')
    imgtrans0_m = mstruct['it1']
    imgtrans1_m = mstruct['it2']
    imgden0_m = mstruct['id1']
    imgden1_m = mstruct['id2']
    scanOr_m = mstruct['scOr'].T - 1

    assert np.isclose(imgtrans0, imgtrans0_m).all()
    assert np.isclose(imgtrans1, imgtrans1_m, atol=1e-4).all() # weird!
    assert np.isclose(imgden0, imgden0_m).all()
    assert np.isclose(imgden1, imgden1_m).all()
    assert np.isclose(scanOr, scanOr_m).all()

def test_get_linear_drift(small_delta_matrix):
    im1, im2 = small_delta_matrix

    # set default values or from input arguments
    linearSearch = np.linspace(-0.02, 0.02, num=2*2+1)
    paddingScale = 1.125
    flagReportProgress = True
    parallel = True
    niter = 2

    # initialise the sMerge object
    scanAngles = (0, 90)
    sm = sMerge(scanAngles, (im1, im2),  paddingScale=paddingScale)

    # get testing linear drifts
    linearSearch *= sm.nr
    inds = np.linspace(-0.5, 0.5, num=sm.nr)[:, None]

    # get linear drift, using the first two images
    xdrift, ydrift = _get_linear_drift(sm, linearSearch, flagReportProgress,
                                       parallel, inds, niter)

    mstruct = sio.loadmat('matlab_result/sMerge_linalig_small_delta_provide_xycoord.mat')
    score_m = mstruct['score']
    xdrift_m, ydrift_m = mstruct['drifts'][0]

    assert np.isclose(sm.linearSearchScores[-1,...], score_m).all()
    assert np.isclose(xdrift, xdrift_m).all()
    assert np.isclose(ydrift, ydrift_m).all()

def test_hanning_weights(small_delta_matrix_sm):
    sm = small_delta_matrix_sm

    padxy = sm.imageSize - sm.img_shape
    nr, nc = sm.img_shape
    hw = _hanning_weight(nr, nc, padxy)

    mstruct = sio.loadmat('matlab_result/sMerge_hanning_weights_small_delta.mat')
    hw_m = mstruct['w2']

    assert np.isclose(hw, hw_m).all()


import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

##################################################
# Initial variable setup
##################################################
# Grab data from source
data_training = pd.read_csv('https://personal.utdallas.edu/~cwk200000/files/auto-mpg-training.csv')
data_test = pd.read_csv('https://personal.utdallas.edu/~cwk200000/files/auto-mpg-test.csv')

# Format the data into x and y axis
X_train = data_training.drop('mpg', axis=1)
y_train = data_training['mpg']
X_test = data_test.drop('mpg', axis=1)
y_test = data_test['mpg']

##################################################
# Function definitions
##################################################

def run_linear_regression():
    # Create a linear regression model
    model = LinearRegression()

    # Fit the model to the training data
    model.fit(X_train, y_train)

    # Predict on the sets
    y_pred_train = model.predict(X_train)
    y_pred_test = model.predict(X_test)

    log_file = open('files/grad_descent_part_2.log', 'w')

    # Evaluate the model using Mean Squared Error (MSE)
    mse_train = mean_squared_error(y_train, y_pred_train)
    mse_test = mean_squared_error(y_test, y_pred_test)
    r2_train = model.score(X_train, y_train)
    r2_test = model.score(X_test, y_test)

    log_entry = ("--- Scikit Linear Regression ---\n"
                f"Weights: {model.coef_}\n"
                f"Training MSE: {mse_train}\n"
                f"Test MSE: {mse_test}\n"
                f"Training R^2: {r2_train}\n"
                f"Test R^2: {r2_test}\n\n")
    log_file.write(log_entry)

    log_file.close()

##################################################
# Main Function
##################################################

if __name__ == '__main__':
    run_linear_regression()


import os
import slack
import logging
from datetime import datetime
from get_parent import get_parent
from support_service import support_service
from case_not_found import case_not_found

logger = logging.getLogger(__name__)

def support_add_comment(channel_id,
                        case,
                        comment,
                        user_id,
                        user_name,
                        allow_alerts=True):
    """
    Add a comment to a Google Cloud support case.

    Parameters
    ----------
    channel_id : str
      unique string used to idenify a Slack channel. Used to send messages to
      the channel
    case : str
      unique id of the case
    comment : str
      comment to be added to the case
    user_id : str
      the Slack user_id of the user who submitted the request. Used to send
      ephemeral messages to the user
    user_name : str
      Slack user_name of the user that ran the command. Appended to the end of
      the comment to identify who submitted it, otherwise all comments will
      show as coming from the case creator
    allow_alerts : bool
      flag to determine whether to silent Slack ephemeral message
    """
    MAX_RETRIES = 3

    service = support_service()

    client = slack.WebClient(token=os.environ.get("SLACK_TOKEN"))

    parent = get_parent(case)

    if parent == "Case not found":
        case_not_found(channel_id, user_id, case)
    else:
        req_body = {
            "body": (comment +
                     (f"\n*Comment submitted by {user_name} via Google Cloud"
                      "Support Slack bot*"))
        }
        req = service.cases().comments().create(parent=parent,
                                                body=req_body)
        slack_response = ""
        try:
            req.execute(num_retries=MAX_RETRIES)
        except BrokenPipeError as e:
            error_message = f"{e} : {datetime.now()}"
            logger.error(error_message)
            slack_response = ("Your comment may not have posted."
                              " Please try again later.")

        else:
            slack_response = ("You added a new comment on case"
                              f" {case}: {comment}")

        finally:
            if allow_alerts:
                client.chat_postEphemeral(channel=channel_id,
                                          user=user_id,
                                          text=slack_response)

if __name__ == "__main__":
    test_channel_id = os.environ.get("TEST_CHANNEL_ID")
    test_case = os.environ.get("TEST_CASE")
    test_comment = ("This is a test comment created by the Google Cloud"
                    " Support Slackbot")
    test_user_id = os.environ.get("TEST_USER_ID")
    test_user_name = os.environ.get("TEST_USER_NAME")
    support_add_comment(test_channel_id, test_case, test_comment, test_user_id,
                        test_user_name)


#!/usr/bin/env python3
import psycopg2

db = psycopg2.connect(database='news')
cur = db.cursor()

def execute_query(title, query, unit):
    cur.execute(query)
    results = cur.fetchall()
    print(title)
    for result in results:
        print(str(result[0]) + '  --->  ' + str(result[1]) + unit)
    print()

titles = []
queries = []
units = []

titles.append('What are the most popular three articles of all time?')
queries.append('select * from article_views order by views desc limit 3;')
units.append(' views')

titles.append('Who are the most popular article authors of all time?')
queries.append('select * from author_views order by views desc limit 4;')
units.append(' views')

titles.append('On which days did more than 1% of requests lead to errors?')
queries.append('select * from error_logs where error > 1;')
units.append(' %')

for title, query, unit in zip(titles, queries, units):
    execute_query(title, query, unit)

db.close()


#=import hgsysinc
#=from hgstat_test_data import (
#=    kma_weather_2010, kosos_drink_2010, kosos_soymilk_2010, kosos_carbonated_drink_2010,
#=)
#-----
#=data_x = [kosos_drink_2010[k] for k in kosos_drink_2010] # 혼합 음료
#=data_y = [kma_weather_2010[k] for k in kma_weather_2010] # 날씨
#=print('data_x:', data_x)
#=print('data_y:', data_y)

# 산포도 : 혼합음료 x 날씨
data_drink = [32122, 36529, 52409, 63650, 72324, 72228, 71971, 69514, 56564, 53861, 45193]
data_weather = [-1.7, 2.3, 5.5, 9.9, 17.1, 22.3, 25.4, 26.9, 21.8, 14.5, 7.1]

#
data_x = data_weather # 날씨
data_y = data_drink # 혼합 음료

title_x = '2010 Weather'
title_y = '2010 Drink',
label_x = 'Weather'
label_y = 'Drink'

title = '2010 ' + label_y + ' & ' + label_x

# 그래프 출력
import matplotlib.pyplot as plt

#=figsize = (10, 5) # 가로 데이터가 많을 때
figsize = (6, 6) # 가로, 세로 데이터 수가 같을 때
#=dotSize = 50
dotSize = 130 # 점을 크게
#
plt.figure(figsize=figsize)
plt.scatter(data_x, data_y, s=dotSize) # 날씨(data_x)를 가로축에
#
plt.xlabel(label_x, fontsize=15)
plt.ylabel(label_y, fontsize=15)
#=plt.legend(loc='upper left')

figure = plt.gcf()
#=figure.canvas.set_window_title(title) # 윈도우 창에 [제목] 보이기
#=#=plt.suptitle(title, fontsize=20, y=1.04) # 이미지 밖의 위쪽에 [제목] 표시
plt.title(title, fontsize=20, y=1.04) # 이미지 밖의 위쪽에 [제목] 표시

#=# 숫자가 클 경우에 라벨 표기가 지수형(exponential)으로 바뀌지 않게
#=plt.ticklabel_format(useOffset=False, style='plain', axis='y')
#
figure.tight_layout() # x,y label 잘리지 않도록
#
plt.show()

#
plt.close() # 이 함수를 호출하지 않으면 다음 호출에 이전 그림이 같이 호출됨.

'''
출력 결과:

#================
#================

data_x: [32122, 36529, 52409, 63650, 72324, 72228, 71971, 69514, 56564, 53861, 45193]
data_y: [-1.7, 2.3, 5.5, 9.9, 17.1, 22.3, 25.4, 26.9, 21.8, 14.5, 7.1

'''


from typing import List

def toposort(node_list: List['Node'], type = 'forward'):
    sorted_graph = [node for node in node_list]
    for node in sorted_graph:
        yield node
        children = node.children if type == 'forward' else node.backward_children
        for child in children:
            if (sorted_graph.count(child)) == 0:
                sorted_graph.append(child)


from pynput import keyboard

def punch():
    print("punch!")

def on_press(key):
    try:
        if key.char == 'f':
            punch()
        else:
            print(f'key pressed: {key.char}')

    except AttributeError:
        print(f'special key pressed: {key}')

def on_release(key):
    print(f'Key released: {key}')
    if key == keyboard.Key.esc:
        return False

#collect events until released
with keyboard.Listener(
        on_press=on_press,
        on_release=on_release) as listener:
    listener.join()


#!/usr/bin/env python
'''
Created in July, 2014
Author: Christoph Grebner
E-Mail: christoph.grebner@astrazeneca.com

program to calculate ANM and PCA for a given set of proteins in PDB format
uses the ProDy library

'''
import prody
import glob
import argparse
import numpy as np

class PCA_ANM_Analysis:
    '''
    class definition for PCA and ANM analysis using ProDy library
    calculate the PCA of a given set of structures and the ANM of the reference structure
    '''
    def __init__(self, selection="calpha"):
        #Initialization of variables with default values
        self.selection=selection
        self.vmd=False
        self.compare=False
        self.ref="none"
        self.debug=False
        self.pdbarg="all"

        self.pdbs = []

    def do_Auto_analysis(self):
        pdbs = self.getPDBs()
        ensemble = self.createEnsemble(pdbs)
        pca = self.calcPCA(ensemble)
        anm = self.calcANM(ensemble.getConformation(0))
        if self.compare:
            self.compare_modes(anm,pca)

    def printSettings(self):
        '''
        Print all settings for debugging purposes
        '''
        env.logger.info("Settings in PCA_ANM_Analysis")
        env.logger.info("selection, VMD, compare, ref, pdb")
        env.logger.info(self.selection, self.vmd, self.compare, self.ref, self.pdbarg)

    def set_default_based_on_argparse(self, selection, vmd, compare, ref, debug, pdb):
        '''
        set arguments from command line based on argparser
        '''
        if selection in ["calpha", "backbone", "all"]:
            self.selection=selection
        else:
            env.logger.info("Invalid value for selection:", selection)
            env.logger.info("Possible Values for selection are: calpha, backbone, all")
            exit()
        self.vmd = vmd
        self.compare=compare
        self.ref=ref
        self.debug=debug
        self.pdbarg=pdb

        #set prody level of output
        if self.debug:
            prody.confProDy(verbosity="debug")
        else:
            prody.confProDy(verbosity="info")

        if self.debug:
            env.logger.info("***DEBUG***")
            self.printSettings()
            env.logger.info("***DEBUG-END***")

    def getPDBs(self):
        '''
        Evaluate information f#from PCA_analysis_GUI import *
from PCA_dPCA import *
rom command line
        Get PDBs and return array
        '''
        if self.pdbarg == "all":
            pdbs = glob.glob('*.pdb')
        else:
            pdbs = self.pdbarg.split()

        if self.debug:
            env.logger.info("***DEBUG*** The chosen PDBs are:", pdbs)
        self.pdbs = pdbs
        return pdbs

    def createEnsemble(self, pdbs, logger):
        '''
        Create a prody ensemble based on getPDBs return
        Take into account, that system can be prepared or not
        and take gaps and multiple chains into account
        take single files and trajectory file into account

        pdbs: list-array with pdb-filenames

        ToDo:
            - set reference depending on longest chain with no gaps
            - check for duplicate chains and only select this one
        '''
        logger.info("Create Ensemble")
        ref_chids = []

        #set the reference structure, if not chosen by user, the first Frame or PDB is taken
        #remove reference Frame/PDB from list
        if self.ref == "none":
            self.ref = pdbs[0]
            pdbs.pop(0)
        else:
            if self.ref in pdbs:
                if self.debug:
                    logger.info("***DEBUG*** Found Ref:", self.ref)
                    logger.info("***DEBUG*** Index Ref", pdbs.index(self.ref))
                    logger.info("Removing reference from pdblist")
                pdbs.pop(pdbs.index(self.ref))

        if self.debug:
            logger.info("***DEBUG*** Reference is",self.ref)

        #open reference file and check for HID, HIE; if found, replace by HIS
        try:
            pdbinfile = open(self.ref)
        except IOError as e:
            env.logger.info(self.ref)
            env.logger.info("I/O error({0}): {1}".format(e.errno, e.strerror))
            exit()

        pdbfiledata = pdbinfile.read()
        for line in pdbinfile:
            if line[17:20] == "HID" or line[17:20] == "HIE":
                env.logger.info("HID or HIE found in pdb-structure. The names will be changed to HIS in the input file")
                break
        pdbinfile.close()

        pdbfiledata = pdbfiledata.replace("HID","HIS")
        pdbfiledata = pdbfiledata.replace("HIE","HIS")

        logger.info("Warning!!! Rewriting reference file {}".format(self.ref))
        pdbfile = open(self.ref,'w')
        pdbfile.write(pdbfiledata)
        pdbfile.close()

        #set reference and create first structure
        if self.selection == "all":
            ref_structure = prody.parsePDB(self.ref)
        else:
            ref_structure = prody.parsePDB(self.ref, subset=self.selection)

        reference_hierview = ref_structure.getHierView()

        logger.info(f"Found {reference_hierview.numChains()} Chain(s) in {reference_hierview._atoms.getTitle()}")
        ensemble_ref_title = reference_hierview._atoms.getTitle()
        logger.info(reference_hierview[0])

        '''
        at the moment all chains are taken
        --> check for duplicate chains and only take on of those
        '''

        for chain in reference_hierview:
            ref_chids.append(chain.getChid())
        if self.debug:
            env.logger.info(f"***DEBUG*** {ref_chids}")

        reference_chains = [reference_hierview[chid] for chid in ref_chids]

        if self.debug:
            env.logger.info(f"***DEBUG*** {reference_chains}")

        ref_chain = reference_chains[0]
        for i in range (1, len(reference_chains), 1):
            ref_chain = ref_chain + reference_chains[i]
        if self.debug:
            env.logger.info("***DEBUG***", ref_chain)
        # save globally
        self.ref_chain = ref_chain
        #Create Ensemble of structures
        ensemble = prody.PDBEnsemble(ensemble_ref_title)
        ensemble.setAtoms(ref_chain)
        ensemble.setCoords(ref_chain)
        #Set ref_structure as first coordinate set
        ensemble.addCoordset(ref_structure)

        if self.debug:
            env.logger.info("***DEBUG***", ref_chain.getResnames())
            env.logger.info("***DEBUG***", ref_chain.getResnums())

        unmapped = []
        # map remaining structures to reference chain and add to ensemble if mapped
        for pdb in pdbs:
             if self.debug:
                 env.logger.info("***DEBUG*** Processing ", pdb)
             if self.selection == "all":
                 #structure = prody.parsePDB(self.ref)
                 structure = prody.parsePDB(pdb)
             else:
                 structure = prody.parsePDB(pdb, subset=self.selection)

             atommaps = []
             for reference_chain in reference_chains:
                 # Map current PDB file to the reference chain
                 mappings = prody.mapOntoChain(structure, reference_chain,
                                         seqid=90,
                                         coverage=50,
                                         subset=self.selection)

                 if len(mappings) == 0:
                     env.logger.info('Failed to map', pdb)
                     break
                 atommaps.append(mappings[0][0])
                 # Make sure all chains are mapped
             if len(atommaps) != len(reference_chains):
                 unmapped.append(pdb)
                 continue
             #env.logger.info(atommaps[0]
             atommap = atommaps[0]
             for i in range (1, len(reference_chains), 1):
                  atommap = atommap + atommaps[i]
             # Add the atommap (mapped coordinates) to the ensemble
             # Note that some structures do not completely map (missing residues)
             # so we pass weights (1 for mapped atoms, 0 for unmapped atoms)
             ensemble.addCoordset(atommap, weights=atommap.getFlags('mapped'))

        if self.debug:
            env.logger.info("***DEBUG*** Number of conformations:", ensemble.numConfs())
            env.logger.info("***DEBUG*** ", ensemble)
            env.logger.info("***DEBUG*** Unmapped structures:", unmapped)
        ensemble.iterpose()

        #env.logger.info(ensemble.getTitle()
        return ensemble

    def setSelections(self, ensemble):
        '''
        put selections also into key arguments
        '''

        custom_selection = False

        if custom_selection == False:
            self.selection_ref_structure = self.ref_chain
            return ensemble
        else:
            self.selection2="name CA"
            structure =  ensemble.getAtoms().select(self.selection2)
            #selec = structure.getSelstr().split()
            selec = structure.getIndices()
            if self.debug:
                env.logger.info("***DEBUG***", selec)
                env.logger.info("***DEBUG***", len(selec))

            #create new ensemble containing only the selected atoms
            ensemble2 = prody.PDBEnsemble(ensemble.getTitle())
            ensemble2.setAtoms(structure)
            ensemble2.setCoords(structure.getCoords())
            self.selection_ref_structure = structure

            #ensemble2.addCoordset(structure)
            for coords in ensemble.iterCoordsets():
                new_coords = np.zeros((ensemble2.numSelected(), 3))
                count = 0
                for coord in range(len(coords)):
                    if coord in selec:
                        new_coords[count] = coords[coord]
                        #env.logger.info(count, new_coords[count]
                        count+=1
                ensemble2.addCoordset(new_coords)

            ensemble2.getConformation(0).setLabel(ensemble2.getTitle())

            if self.debug:
                env.logger.info("***DEBUG*** Ensemble before selections: ", repr(ensemble))
                env.logger.info("***DEBUG*** Ensemble after selections: ", repr(ensemble2))

            return ensemble2

    def setWeights(self, ensemble):
        '''
        create a custom selection (e.g. only specific residues) and set the weights for the remaining atoms
        to 0
        --> They will not contribute to the PCA
        the original ensemble is not changed!
        '''
        env.logger.info("Set weights")
        self.selection2="(backbone)"
        structure =  ensemble.getAtoms().select(self.selection2)
        #selec = structure.getSelstr().split()
        selec = structure.getIndices()
        #set weights for atoms outside selection to zero!
        weights =  ensemble.getWeights()
        for i in range(1,len(weights)):
            for j in range(len(weights[i])):
                #set atoms in selection to 1 rest to 0
                if j not in selec:
                    weights[i][j] = 0
                #env.logger.info(j, weights[i][j]

        ensemble.setWeights(weights)

        return ensemble

    def calcPCA(self, ensemble, logger):
        '''
        calcPCA:
        #ensemble: prody ensmeble with structure information

        calculate PCA for a set of structures

        return: prody.pca object
        '''
        logger.info("Calculate PCA")

        PCAname = ensemble.getTitle()
        pca = prody.PCA(PCAname)
        pca.buildCovariance(ensemble)

        logger.info("PCA")
        pca.calcModes()
        logger.info(repr(pca))

        outputname = PCAname + "_pca_modes.nmd"

        prody.writeNMD(outputname, pca[:10], self.selection_ref_structure)

        if self.vmd == True:
            prody.viewNMDinVMD(outputname)
        logger.info(f"PCA is saved in: {outputname}")
        return pca, outputname

    def calcANM(self, structure, logger):
        '''
        calcANM:
        #structure: prody PDB-structure

        calculate ANM for one specific structure

        return: prody.anm object
        '''
        logger.info("Calculate ANM")
        ANMname = structure.getLabel()
        anm = prody.ANM(ANMname)
        anm.buildHessian(structure, cutoff=15.0)
        anm.calcModes()
        # write out the three lowest modes as NMD file (visualize with NMWizard in VMD
        outputname = ANMname + "_anm_modes.nmd"
        prody.writeNMD(outputname, anm[:10], self.selection_ref_structure)
        if self.vmd == True:
            prody.viewNMDinVMD(outputname)
        logger.info(f"ANM is saved in: {outputname}")
        return anm

    def compare_modes(self, modes1, modes2):
        '''
        Compare the calculated ANM and PCA
        '''

        env.logger.info(self.print_Eigen_Val_Vec(modes1))
        env.logger.info(self.print_Eigen_Val_Vec(modes2))

        prody.printOverlapTable(modes2[:3], modes1[:3]) # Top 3 PCs vs slowest 3 ANM modes

        for mode in modes2[:10]:
            var = prody.calcFractVariance(mode).round(3)
            env.logger.info('{0:s}  % variance = {1:.2f}'.format(mode, var))
            coll = prody.calcCollectivity(mode)
            env.logger.info('{0:s}  collectivity = {1:.2f}'.format(mode, coll))

        for mode in modes1[:10]:    # Print ANM mode collectivity
            var = prody.calcFractVariance(mode).round(3)
            env.logger.info('{0:s}  % variance = {1:.2f}'.format(mode, var))
            coll = prody.calcCollectivity(mode)
            env.logger.info('{0:s}  collectivity = {1:.2f}'.format(mode, coll))

    def print_Eigen_Val_Vec(self,mode):
        env.logger.info("Eigenvalues of", mode.getModel())
        env.logger.info(mode.getEigvals().round(3))
        env.logger.info("Eigenvectors of", mode.getModel())
        env.logger.info(mode.getEigvecs().round(3))

    def print_Match(self, match):
       env.logger.info('Chain 1     : {}'.format(match[0]))
       env.logger.info('Chain 2     : {}'.format(match[1]))
       env.logger.info('Length      : {}'.format(len(match[0])))
       env.logger.info('Seq identity: {}'.format(match[2]))
       env.logger.info('Seq overlap : {}'.format(match[3]))
       env.logger.info('RMSD        : {}\n'.format(calcRMSD(match[0], match[1])))

    def print_modes(self, modes):
        env.logger.info("Printing modes to file")
        import matplotlib.pyplot as plt
        residues = self.ref_chain.getResnums()
        print_offset = residues[0]
        plt.rcParams.update({'font.size': 14})

        for count in range(len(modes)):
            #array with lenghts of vectors
            a3d = (modes[count].getArrayNx3()**2).sum(axis=1)**0.5
            plt.plot(a3d[:])
            plt.xlabel('Residue index')
            plt.ylabel('Lenght of fluctuation vector')
            locs,labels = plt.xticks()
            new_labels = ['%d' % (a+print_offset) for a in locs]
            plt.xticks(locs,new_labels)
            plt.title(str(modes)+" mode "+str(count+1))
            plt.savefig(str(modes)+"_mode_"+str(count)+".pdf")
            plt.clf()

        for count in range(6):
            #array with lenghtes of vectors
            a3d = (modes[count].getArrayNx3()**2).sum(axis=1)**0.5
            plt.plot(a3d[:], label=("Mode "+str(count+1)))

        plt.xlabel('Residue index')
        plt.ylabel('Lenght of fluctuation vector')

        locs,labels = plt.xticks()
        new_labels = ['%d' % (a+print_offset) for a in locs]
        plt.xticks(locs,new_labels)
        lgd = plt.legend(loc='center right', bbox_to_anchor=(1.3,0.5))
        plt.savefig(str(modes)+"_mode_1_to_6.pdf", bbox_extra_artists=(lgd, ), bbox_inches='tight')

        env.logger.info("Printing modes to file finished")

    def print_diff(self, pca_modes, anm_modes):
        env.logger.info("here I am in DIFF")
        import matplotlib.pyplot as plt
        from matplotlib.path import Path
        import matplotlib.patches as patches
        residues = self.ref_chain.getResnums()
        print_offset = residues[0]
        #Paper01:PCA-X-Ray:
        print_offset = 738
        plt.rcParams.update({'font.size': 24})
        plt.rcParams['xtick.major.pad'] = 10
        plt.rcParams['ytick.major.pad'] = 10

        a3d_pca = ((pca_modes[0].getArrayNx3())**2).sum(axis=1)**0.5
        a3d_anm = ((anm_modes[0].getArrayNx3())**2).sum(axis=1)**0.5
        a3d_all = a3d_pca - a3d_anm
        for count in range(1,6):
            #array with lenghts of vectors
            a3d_pca = ((pca_modes[count].getArrayNx3())**2).sum(axis=1)**0.5
            a3d_anm = ((anm_modes[count].getArrayNx3())**2).sum(axis=1)**0.5
            a3d_all = a3d_all + a3d_pca - a3d_anm

        plt.plot(a3d_all[:], label=("Difference"), lw=1.5)
        plt.xlabel('Residue index')
        plt.ylabel('|PCA| - |ANM|')
        locs,labels = plt.xticks()
        new_labels = ['%d' % (a+print_offset) for a in locs]
        plt.xticks(locs,new_labels)
        lgd = plt.legend(loc='center right', bbox_to_anchor=(1.65,0.5))
        ##add boxes
        codes = [Path.MOVETO,
                  Path.LINETO,
                  Path.LINETO,
                  Path.LINETO,
                  Path.CLOSEPOLY,
                  ]
        ### light green
        verts = [
                 (95, -2.0), # left, bottom
                 (95, 2.0), # left, top
                 (115, 2.0), # right, top
                 (115, -2.0), # right, bottom
                 (0., 0.), # ignored
                 ]
        path = Path(verts, codes)
        #add box around area of interest
        ax = plt.subplot()
        patch = patches.PathPatch(path, facecolor='#CCFFCC', lw=1)
        #patch = patches.PathPatch(path, facecolor='lightgreen', lw=1)
        ax.add_patch(patch)
        plt.axhline(y=0.0,xmin=0,xmax=3,c="black",linewidth=1.0,zorder=0)
        plt.savefig(str(pca_modes)+"_all_DIFF.pdf", bbox_extra_artists=(lgd, ), bbox_inches='tight')
        plt.clf()

        for count in range(6):
            #array with lenghtes of vectors
            a3d = ((pca_modes[count].getArrayNx3())**2).sum(axis=1)**0.5 - ((anm_modes[count].getArrayNx3())**2).sum(axis=1)**0.5
            plt.plot(a3d[:], label=("Mode "+str(count+1)), lw=1.5)
        plt.xlabel('Residue index')
        plt.ylabel('|PCA| - |ANM|')
        locs,labels = plt.xticks()
        new_labels = ['%d' % (a+print_offset) for a in locs]
        plt.xticks(locs,new_labels)
        lgd = plt.legend(loc='center right', bbox_to_anchor=(1.65,0.5))

        ##add boxes
        codes = [Path.MOVETO,
                  Path.LINETO,
                  Path.LINETO,
                  Path.LINETO,
                  Path.CLOSEPOLY,
                  ]
        ### light green
        verts = [
                 (95, -0.7), # left, bottom
                 (95, 0.7), # left, top
                 (115, 0.7), # right, top
                 (115, -0.7), # right, bottom
                 (0., 0.), # ignored
                 ]

        path = Path(verts, codes)
        #add box around area of interest
        ax = plt.subplot()
        patch = patches.PathPatch(path, facecolor='#CCFFCC', lw=1)
        ax.add_patch(patch)
        plt.axhline(y=0.0,xmin=0,xmax=3,c="black",linewidth=1.0,zorder=0)
        plt.savefig(str(pca_modes)+"_ANM_PCA_DIFF.pdf", bbox_extra_artists=(lgd, ), bbox_inches='tight')

    def print_from_file(self, modesfile):
        env.logger.info("Printing modes from file", modesfile)
        import matplotlib.pyplot as plt
        from matplotlib.path import Path
        import matplotlib.patches as patches
        modes, atm_group = prody.parseNMD(modesfile)

        title=modesfile.split(".")
        modes.setTitle(title[0])
        print_offset = 1
        #print_offset = 738
        plt.rcParams.update({'font.size': 24})
        plt.rcParams['xtick.major.pad'] = 10
        plt.rcParams['ytick.major.pad'] = 10

        for count in range(6):
            #array with lenghtes of vectors
            a3d = (modes[count].getArrayNx3()**2).sum(axis=1)**0.5
            plt.plot(a3d[:], label=("Mode "+str(count+1)))
        plt.xlabel('Residue index')
        plt.ylabel('Lenght of fluctuation vector')

        locs,labels = plt.xticks()
        new_labels = ['%d' % (a+print_offset) for a in locs]
        plt.xticks(locs,new_labels)
        plt.ylim([0,0.8])
        plt.xlim([print_offset, modes.numAtoms()])

        lgd = plt.legend(loc='center right', bbox_to_anchor=(1.6,0.5))
        plt.savefig(str(modes.getTitle())+"_mode_1_to_6.pdf", bbox_extra_artists=(lgd, ), bbox_inches='tight')

        env.logger.info("Printing modes to file finished")

def parse_Arguments():
    '''
    parsing of command line arguments
    '''
    parser = argparse.ArgumentParser(
        description='Calculate PCA and ANM for given structures',
        epilog="", formatter_class=SmartFormatter)
    parser.add_argument("--pdb", help="""R|specify the pdbs which should be used.
            Important!!!: They will be overwritten by Prody to match its PDB format,
            in particular histidine names.
            If not specified, all PDBs in the current folder are taken by default.
            Possibilities:
            use all PDBs in directory: --pdb all
            give a list of PDBs, either single or trajectory file: --pdb "name1.pdb name2.pdb name3.pdb name4.pdb"
            """, default='all')
    parser.add_argument("--selection", help="""R|Specify the selection for normal mode analysis
            valid options:
            --selection "calpha":
            --selection "backbone"
            --selection "all"
    """, default='calpha')
    parser.add_argument("--compare", help="compare PCA and ANM", action="store_true", default=False)
    parser.add_argument("--vmd", help="Visualize result in VMD", action="store_true", default=False)
    parser.add_argument("--debug", help="Print debug information", action="store_true", default=False)
    parser.add_argument("--ref", help="Select a reference structure for PCA and ANM", default='none')
    parser.add_argument("--print_mode", help="Print the square fluctuations of the modes", action="store_true", default=False)
    parser.add_argument("--print_diff", help="Print difference between ANM and PCA modes", action="store_true", default=False)
    parser.add_argument("--print_file", help="Print modes from a NMD file. This will exit the program after printing", default='none')
    parser.add_argument("--anm_only", help="Only perform ANM analysis", action="store_true", default=False)
    return parser.parse_args()

class SmartFormatter(argparse.HelpFormatter):
    """
    Helper class for argparse
    help beginning with R| will be parsed with new lines
    """
    def _split_lines(self, text, width):
        # this is the RawTextHelpFormatter._split_lines
        if text.startswith('R|'):
            return text[2:].splitlines()
        return argparse.HelpFormatter._split_lines(self, text, width)

def main(pdb, selection='calpha', vmd=False, compare=False, ref="none", debug=False, logger=None):

    logger.info("\n\nWarning!!! Reference PDB file, if provided, will be rewritten in"
          " ProDy PDB format, with HID and HIE residues renamed to HIS.\n\n")
    pdb = " ".join(pdb)

    # create PCA_analysis object
    Analysis = PCA_ANM_Analysis()
    Analysis.set_default_based_on_argparse(selection, vmd, compare, ref, debug, pdb)

    pdbs = Analysis.getPDBs()
    ensemble = Analysis.createEnsemble(pdbs, logger)
    # set weights for the PCA analysis
    # ensemble = Analysis.setWeights(ensemble)
    ensemble = Analysis.setSelections(ensemble)

    pca, pca_modes = Analysis.calcPCA(ensemble, logger)
    anm = Analysis.calcANM(ensemble.getConformation(0), logger)

    if Analysis.compare:
        Analysis.compare_modes(anm,pca)

    return pca_modes

if __name__ == '__main__':
    # parse command line options and create help
    args = parse_Arguments()
    main(args.pdb, args.selection, args.vmd, args.compare, args.ref, args.debug)

{'plt': 'matplotlib.pyplot', 'Path': 'matplotlib.path.Path', 'patches': 'matplotlib.patches'}


import imaplib
import email
from email.header import decode_header, make_header

server = imaplib.IMAP4_SSL('imap.gmail.com')
server.login('your_gmail_id', 'your_gmail_passwd')

rv, data = server.select()
recent_no = data[0]

rv, fetched = server.fetch(recent_no, '(RFC822)')
message = email.message_from_bytes(fetched[0][1])

fr = make_header(decode_header(message.get('From')))
subject = make_header(decode_header(message.get('Subject')))

if message.is_multipart():
    for part in message.walk():
        ctype = part.get_content_type()
        cdispo = str(part.get('Content-Disposition'))
        if ctype == 'text/plain' and 'attachment' not in cdispo:
            body = part.get_payload(decode=True)
            break
else:
    body = message.get_payload(decode=True)

body = body.decode('utf-8')

print(f"보낸사람:{fr}")
print(f"제목:{subject}")
print(f"내용:{body}")

server.close()
server.logout()


import pytest
import discord
from src.discord_object_converter.abstract import AbstractPermissionConverter
from src.discord_object_converter.permission import PermissionConverter

@pytest.mark.asyncio
@pytest.mark.parametrize(('key', 'value'), [
    ('リアクションの追加', 'OK'),
    ('管理者', 'NG'),
    ('埋め込みリンク', 'OK')
])
async def test_permission_converter(key, value):
    perm = discord.Permissions(permissions=1275879617)
    convert_result = PermissionConverter.convert(perm)
    assert convert_result[key] == value


from tweepy import StreamListener
from tweepy import OAuthHandler
from tweepy import Stream
from keys import TwitterKeys
import tweepy

""" Find twitter user ID from username using twitter API
GET https://api.twitter.com/1/users/lookup.json?screen_name=somename
"""

""" This file should be used to stream Twitter JSON data from Twitter into text
files for further manipulation by the tweet_nltk.py file. Currently, it allows
for the user to input the Twitter ID number in the terminal in order to choose
what user's tweets will be streamed.
"""

# Variables for logging in to Twitter
def keys(access_token, access_token_secret, consumer_key, consumer_secret):
    access_token = TwitterKeys.access_token
    access_token_secret = TwitterKeys.access_token_secret
    consumer_key = TwitterKeys.consumer_key
    consumer_secret = TwitterKeys.consumer_secret
    return keys(access_token, access_token_secret, consumer_key, consumer_secret)

# Variables for authorization
auth = tweepy.OAuthHandler(TwitterKeys.consumer_key, TwitterKeys.consumer_secret)
auth.set_access_token(TwitterKeys.access_token, TwitterKeys.access_token_secret)
api = tweepy.API(auth)

# Defines class that takes JSON data from Twitter stream and write to .txt file
class StdOutListener(StreamListener):

    # Twitter stream function: sends streamed tweets to .txt file
    def on_data(self, data):
        print(data)
        # Lines 34-35 unused, kept for future reference
        # print(status.text())
        # print(status.user.screen_name())
        # Write contents of 'data' variable to twitterstream_results.txt
        with open('twitterstream_results.txt','a') as textfile:
            textfile.write(data)
        return True

    # Error handler for the Twitter stream
    def on_error(self, status):
        print(status)
        # Write status message (e.g. error 406) to file on error
        with open('twitterstream_results.txt','a') as textfile:
            textfile.write(status)

if __name__ == '__main__':

    # Handles Twitter authentification & connection to Twitter Streaming API
    l = StdOutListener()
    auth = OAuthHandler(TwitterKeys.consumer_key, TwitterKeys.consumer_secret)
    auth.set_access_token(TwitterKeys.access_token, TwitterKeys.access_token_secret)
    stream = Stream(auth, l)

    # Streams tweets using Twitter ID number via input from user in the command-line
    stream.filter(follow=input('''Please enter a Twitter user\'s ID number in the format ['1234567'], including the opening and closing brackets and quotes: '''))

    # Below is the previous stream via Twitter ID without input for reference:
    # stream.filter(follow=['1367531'])


#!/usr/bin/env python

##########################################################################
#
#   stress analysis routine, v0.1 01/2017
#
#   by xiangchen@acm.org
#
#   ! require numpy, pysparse
#
##########################################################################

from __future__ import print_function

import time as time

T = int(round(time.time() * 1000))
t0 = T

def _log(msg):
    global T
    t = int(round(time.time() * 1000))
    if msg != None:
        print(msg + ': ' + str(t - T) + 'ms')
    T = t
    return t

_log(None)

from sys import argv
import argparse
import json
import ast
import numpy as np
from math import sqrt
from pysparse import spmatrix, itsolvers, precon, superlu
import struct

_log('importing everything')

Ke = np.load('H8.K')
B = np.matrix(np.load('H8.B'))
C = np.matrix(np.load('H8.C'))

_log('global constant variables')

def _save(data, name):
    f = open(name, 'w')
    f.write(str(data))
    f.close()
    print('saved to ' + name)

def _node_nums_3d(nelx, nely, nelz, mpx, mpy, mpz):
    """
    adopted from Topy (https://github.com/williamhunter/topy)
    compute node number based on element number
    """
    innback = np.array([0, 1, nely + 1, nely + 2])  # initial node numbers at back
    enback = nely * (mpx - 1) + mpy
    nnback = innback + enback + mpx - 1
    nnfront = nnback + (nelx + 1) * (nely + 1)
    nn = np.hstack((nnback, nnfront)) + (mpz - 1) * (nelx + 1) * (nely + 1)
    return nn

def _sub(u, v):
    return [u[0] - v[0], u[1] - v[1], u[2] - v[2]]

def _dot(u, v):
    return u[0] * v[0] + u[1] * v[1] + u[2] * v[2]

def _cross(u, v):
    return [u[1] * v[2] - u[2] * v[1], u[0] * v[2] - u[2] * v[0], u[0] * v[1] - u[1] * v[0]]

def _normsq(v):
    return v[0] * v[0] + v[1] * v[1] + v[2] * v[2]

def _on_same_side(p1, p2, a, b):
    """
    compute if p1 and p2 are on the same side as segment ab
    """
    ab = _sub(b, a)
    cp1 = _cross(ab, _sub(p1, a))
    cp2 = _cross(ab, _sub(p2, a))

    sameside = False
    if _normsq(cp1) != 0 or _normsq(cp2) != 0:
        sameside = _dot(cp1, cp2) > 0
    else:
        sameside = True

    return sameside

def _in_triangle(v, va, vb, vc):
    """
    tell if v is inside a triangle define by va, vb and vc
    """
    return _on_same_side(v, va, vb, vc) and \
        _on_same_side(v, vb, va, vc) and \
        _on_same_side(v, vc, va, vb)

def _voxelize(bstl, n):
    """
    voxelize a mesh
    input:
        bstl - path to a binary stl file
        n    - max # of voxels along x, y and z
    return:
        said triangles
    reference:
        loading triangles from an stl file, adopted from https://github.com/arizonat/py-stl-toolkit
    """
    _log(None)

    print('loading stl file ......', end='')
    try:
        f = open(bstl, 'rb')
    except IOError:
        raise TypeError('must be the path to a mesh file')

    header = f.read(80)
    numTriangles = struct.unpack("@i", f.read(4))
    numTriangles = numTriangles[0]

    triangles = [(0, 0, 0)] * numTriangles  # prealloc, slightly faster than append
    norms = [(0, 0, 0)] * numTriangles
    bytecounts = [(0, 0, 0)] * numTriangles

    for i in xrange(numTriangles):
        norms[i] = struct.unpack("<3f", f.read(12))
        vertex1 = struct.unpack("<3f", f.read(12))
        vertex2 = struct.unpack("<3f", f.read(12))
        vertex3 = struct.unpack("<3f", f.read(12))
        bytecounts[i] = struct.unpack("H", f.read(2))  # not sure what this is

        triangles[i] = (vertex1, vertex2, vertex3)

    # compute voxel dimension
    INF = float('inf')
    vmin = [INF, INF, INF]
    vmax = [-INF, -INF, -INF]
    centers = []
    for t in triangles:
        ctr = [0, 0, 0]
        for v in t:
            for i in range(0, 3):
                vmin[i] = min(v[i], vmin[i])
                vmax[i] = max(v[i], vmax[i])
                ctr[i] += v[i] / 3
        centers.append(ctr)

    dim = max(vmax[0] - vmin[0], vmax[1] - vmin[1], vmax[2] - vmin[2]) / n
    nx = int((vmax[0] - vmin[0]) / dim + 0.5)
    ny = int((vmax[1] - vmin[1]) / dim + 0.5)
    nz = int((vmax[2] - vmin[2]) / dim + 0.5)

    _log('done')
    print('num of triangles', len(triangles))

    vxg = []

    # per voxel ray casting
    NUMDIR = 3
    cntr = 1
    for i in range(0, nz):
        vxgplane = []
        for j in range(0, ny):
            vxgrow = []
            for k in range(0, nx):
                perc = cntr * 100.0 / (nx * ny * nz)
                print('voxelizing ............ ' + str(int(perc)) + '%', end='\r')

                ctrvoxel = [vmin[0] + (k + 0.5) * dim, vmin[1] + (j + 0.5)
                            * dim, vmin[2] + (i + 0.5) * dim]
                counter = [[0, 0], [0, 0], [0, 0]]
                for h in range(0, len(triangles)):
                    t = triangles[h]
                    ctrface = centers[h]
                    for l in range(0, NUMDIR):
                        projctrvoxel = list(ctrvoxel)
                        projva, projvb, projvc = list(t[0]), list(t[1]), list(t[2])
                        if l == 0:
                            projctrvoxel[0] = 0
                            projva[0] = 0
                            projvb[0] = 0
                            projvc[0] = 0
                            if _in_triangle(projctrvoxel, projva, projvb, projvc):
                                counter[l][0 if ctrvoxel[0] < ctrface[0] else 1] += 1
                        elif l == 1:
                            projctrvoxel[1] = 0
                            projva[1] = 0
                            projvb[1] = 0
                            projvc[1] = 0
                            if _in_triangle(projctrvoxel, projva, projvb, projvc):
                                counter[l][0 if ctrvoxel[1] < ctrface[1] else 1] += 1
                        elif l == 2:
                            projctrvoxel[2] = 0
                            projva[2] = 0
                            projvb[2] = 0
                            projvc[2] = 0
                            if _in_triangle(projctrvoxel, projva, projvb, projvc):
                                counter[l][0 if ctrvoxel[2] < ctrface[2] else 1] += 1

                isvoxel = False
                for l in range(0, NUMDIR):
                    if counter[l][0] % 2 == 1 and counter[l][1] % 2 == 1:
                        isvoxel = True
                        break
                vxgrow.append(1 if isvoxel else 0)
                cntr += 1
            vxgplane.append(vxgrow)
        vxg.append(vxgplane)

    print('')
    _log('done')
    return {'dimvoxel': dim, 'voxelgrid': vxg}

def _load_vxg(vxgpath):
    """
    load a voxel grid file
    """
    vxgraw = open(vxgpath, 'r').read()
    idxdim = vxgraw.index('\n')
    dim = float(vxgraw[:idxdim])
    vxgraw = vxgraw[idxdim + 1:]
    vxg = ast.literal_eval(vxgraw)
    return vxg

def analyze(vxg, loads, boundary, iter):
    """
    main analysis function
       - vxg: voxel grid (3d list)
       - loads: each consisting of
           * points [point set #1, point set #2 ...]
           * value [value #1, value #2, ...]
       - boundary
           * points
       - iter: whether to use iterative or direct solver
        (points are element numbers)
    output:
       - displacement vector
       - von Mises stress vector
    """
    global Ke, B, C

    nz = len(vxg)
    ny = len(vxg[0])
    nx = len(vxg[0][0])
    _log('voxelization')
    print('voxel grid: ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz))

    # compute stiffness matrix for individual elements
    DOF = 3
    ksize = DOF * (nx + 1) * (ny + 1) * (nz + 1)
    kall = spmatrix.ll_mat_sym(ksize, ksize)

    SOLID = 1.000
    VOID = 0.001
    for i in range(0, nz):
        for j in range(0, ny):
            for k in range(0, nx):
                xe = SOLID if vxg[i][j][k] == 1 else VOID
                nodes = _node_nums_3d(nx, ny, nz, k + 1, j + 1, i + 1)
                ind = []
                for n in nodes:
                    ind.extend([(n - 1) * DOF, (n - 1) * DOF + 1, (n - 1) * DOF + 2])
                mask = np.ones(len(ind), dtype=int)
                kall.update_add_mask_sym(Ke * xe, ind, mask)

    _log('updated stiffness matrix for all elements')

    # formulate loading scenario
    rall = [0] * ksize
    indicesset = loads['points']
    values = loads['values']

    for i in range(0, len(indicesset)):
        indices = indicesset[i]
        value = values[i]
        for idx in indices:
            nodes = _node_nums_3d(nx, ny, nz, idx[0] + 1, idx[1] + 1, idx[2] + 1)
            for j in range(0, DOF):
                for k in range(0, len(nodes)):
                    rall[DOF * (nodes[k] - 1) + j] = value[j]

    # formulate boundary condition
    elemmask = [1] * (nx + 1) * (ny + 1) * (nz + 1)
    for idx in boundary:
        nodes = _node_nums_3d(nx, ny, nz, idx[0] + 1, idx[1] + 1, idx[2] + 1)
        for j in range(0, len(nodes)):
            elemmask[nodes[j] - 1] = 0

    freedofs = []
    fixeddofs = []
    for i in range(0, len(elemmask)):
        if elemmask[i] == 1:
            freedofs.extend((DOF * i, DOF * i + 1, DOF * i + 2))
        else:
            fixeddofs.extend((DOF * i, DOF * i + 1, DOF * i + 2))

    _log('formulated loading scenario and boundary condition')

    # solve KU=F
    rfree = np.take(rall, freedofs)
    dfree = np.empty(len(freedofs))

    alldofs = np.arange(ksize)
    rcfixed = np.where(np.in1d(alldofs, fixeddofs), 0, 1)
    kfree = kall
    kfree.delete_rowcols(rcfixed)

    _log('removed constrained elements')

    if iter:
        kfree = kfree.to_sss()
        prek = precon.ssor(kfree)
        (info, numitr, relerr) = itsolvers.pcg(kfree, rfree, dfree, 1e-8, 8000, prek)
        if info >= 0:
            print('converged after ' + str(numitr) + ' iterations with error of ' + str(relerr))
        else:
            print('PySparse error: Type:' + info + ', at' + str(numitr) + 'iterations.')
    else:
        kfree = kfree.to_csr()
        lu = superlu.factorize(kfree)
        lu.solve(rfree, dfree)

    _log('solved KU=F')

    dall = np.zeros_like(rall)
    for i in range(0, len(freedofs)):
        dall[freedofs[i]] = dfree[i]

    # compute stress
    cb = C * B
    vonmises = []
    for i in range(0, nz):
        vmplane = []
        for j in range(0, ny):
            vmrow = []
            for k in range(0, nx):
                nodes = _node_nums_3d(nx, ny, nz, k + 1, j + 1, i + 1)
                disps = []
                for n in nodes:
                    disps.extend([dall[DOF * (n - 1)], dall[DOF * (n - 1) + 1],
                                  dall[DOF * (n - 1) + 2]])
                d = np.matrix(disps).transpose()
                sigma = cb * d

                s11 = sigma.item(0, 0)
                s22 = sigma.item(1, 0)
                s33 = sigma.item(2, 0)
                s12 = sigma.item(3, 0) * 0.5        # DOUBLE CHECK THIS
                s23 = sigma.item(4, 0) * 0.5
                s31 = sigma.item(5, 0) * 0.5

                # von Mises stress, cf. Strava et al.'s Stress Relief paper (SIGGRAPH '12)
                vmrow.append(sqrt(0.5 * ((s11 - s22)**2 + (s22 - s33)**2 + (s33 - s11)**2 +
                                         6 * (s12**2 + s23**2 + s31**2))))
            vmplane.append(vmrow)
        vonmises.append(vmplane)

    t1 = _log('computed stress')

    global t0
    print('total time:' + str(t1 - t0) + ' ms')

    return {'displacements': dall.tolist(), 'stress': vonmises}

if __name__ == "__main__":
    """
    main function entry point
    """
    # setting up parameters
    parser = argparse.ArgumentParser(description='stress analysis')
    parser.add_argument('path', metavar='path', type=str,
                        help='path to a .stl (mesh) or .vxg (voxel grid) file')
    parser.add_argument('-d', dest='dimension', nargs='?', default=32,
                        help='dimension of the voxel grid (if want to perform voxelization, default is 32)')
    parser.add_argument('-c', dest='config',
                        help='path to a configuration file (.json) describing loading scenario and boundary condition')
    parser.add_argument('-o', dest='output', nargs='?', default='result',
                        help='output path for analysis results: displacements and stress')
    args = parser.parse_args()

    # parsing configuration
    config = json.loads(open(args.config, 'r').read())
    boundary = config['boundary']
    loads = {'points': config['loadpoints'], 'values': config['loadvalues']}

    # creating or loading voxel grid
    vxg = None
    if args.path.endswith('.stl'):
        vxginfo = _voxelize(args.path, int(args.dimension))
        vxg = vxginfo['voxelgrid']
        _save(str(vxginfo['dimvoxel']) + '\n' + str(vxg),
              args.path.split('.')[0] + '_' + str(args.dimension) + '.vxg')
    elif args.path.endswith('.vxg'):
        vxg = _load_vxg(args.path)
    else:
        raise TypeError('must be .stl (mesh) or .vxg (voxel grid) file')

    # performing analysis
    if vxg != None:
        result = analyze(vxg, loads, boundary, True)
        if args.output != None:
            _save(result['displacements'], args.output + '.disp')
            _save(result['stress'], args.output + '.strs')
    else:
        raise ValueError('cannot create or load voxel grid')


from collections import OrderedDict

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

from torch.jit.annotations import Tuple, List, Dict

class IntermediateLayerGetter(nn.ModuleDict):
    """
    IntermediateLayerGetter 类，它是一个 PyTorch 模型的包装器，可以用于提取模型中间层的特征输出。
    该类的主要作用是在给定的模型中提取指定子模块的特征，并将其按照指定的名称进行输出。
    获取一个Model中你指定要获取的哪些层的输出
    # 这个方法跟create_feature_extractor功能类似，但是这个只能获取一级子模块，无法获得下一级，因此常用create_feature_extractor
    """
    __annotations__ = {
        "return_layers": Dict[str, str]
    }

    def __init__(self, model, return_layers):
        if not set(return_layers).issubset([name for name, _ in model.named_children()]):
            raise ValueError("return_layers are not present in model")

        orig_return_layers = return_layers
        return_layers = {str(k): str(v) for k, v in return_layers.items()}
        layers = OrderedDict()

        for name, module in model.named_children():
            layers[name] = module
            if name in return_layers:
                del return_layers[name]
            if not return_layers:
                break

        super(IntermediateLayerGetter, self).__init__(layers)
        self.return_layers = orig_return_layers

    def forward(self, x):
        out = OrderedDict()
        # 遍历model的子模块，进行正向传播
        # 收集layer1，layer2，layer3，layer4的输出
        for name, module in self.items():
            x = module(x)
            if name in self.return_layers:
                out_name = self.return_layers[name]
                out[out_name] = x
        return out

class FeaturePyramidNetwork(nn.Module):
    """
    FPN网络模块，网络的输入为OrderDict的feature maps
    Argument:
        in_channels_list: 每一个feature map的channel
        out_channels: FPN的channel
        extra_block：同BackboneWithFPN
    """

    def __init__(self, in_channels_list, out_channels, extra_block):
        super(FeaturePyramidNetwork, self).__init__()

        self.inner_blocks = nn.ModuleList()

        self.layer_blocks = nn.ModuleList()

        for in_channels in in_channels_list:
            if in_channels == 0:
                continue
            # 每一个feature map出来后调整一次out_channels
            inner_block_module = nn.Conv2d(in_channels, out_channels, 1)
            # 然后在经过3*3的卷积，形状不变
            layer_block_module = nn.Conv2d(out_channels, out_channels, 3, padding=1)
            self.inner_blocks.append(inner_block_module)
            self.layer_blocks.append(layer_block_module)
        # 将FPN这几层机型初始化
        for m in self.children():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal(m.weight, a=1)
                nn.init.constant_(m.bias, 0)

        self.extra_block = extra_block

    def get_result_from_inner_blocks(self, x: Tensor, idx: int) -> Tensor:
        """
        用于获取在 FPN 中某个特定的 inner block 的输出结果。
        :param x:
        :param idx:
        :return:
        """
        num_blocks = len(self.inner_blocks)
        if idx <= 0:
            idx += num_blocks
        i = 0
        out = x
        for module in self.inner_blocks:
            if i == idx:
                out = module(x)
            i += 1
        return out

    def get_result_from_layer_blocks(self, x: Tensor, idx: int) -> Tensor:

        num_blocks = len(self.layer_blocks)
        if idx < 0:
            idx += num_blocks

        i = 0
        out = x
        for module in self.layer_blocks:
            if i == idx:
                out = module(x)
            i += 1
        return out

    def forward(self, x: Dict[str, Tensor]) -> Dict[str, Tensor]:
        """
        OrderDict feature maps经FPN计算, FPN将这组特征图上采样到一个共同的分辨率，并对其进行融合，以产生具有不同分辨率的特征图。
        这里对于输入的feature map，前面的（高分辨率的）都融合了其后面的信息，方法是将后面的那一层上采样2倍之后相加。这与yolo中略有不同。
        eg:
            假设输入的return_layers={"0": "layer1", "1": "layer2", "2": "layer3"}，则输出的tensor_fpn一共有3个，
            分别对应layer1、layer2和layer3三个特征层的融合结果。
            具体的融合过程如下，从后向前：
                1、对于layer3特征层，经过self.inner_blocks[2]卷积层进行通道数的调整，得到last_inner。
                2、对于layer3特征层，先将last_inner作为该层对应的预测特征层self.layer_blocks[2]的输入，得到out_layer3。
                3、对于layer2特征层，先通过self.inner_blocks[1]卷积层进行通道数的调整，得到inner_lateral2。然后将last_inner上采样
                   至inner_lateral2的大小，再将其与inner_lateral2相加，得到融合后的特征层top_down_layer2。
                4、对于layer2特征层，将top_down_layer2作为该层对应的预测特征层self.layer_blocks[1]的输入，得到out_layer2。
                5、对于layer1特征层，先通过self.inner_blocks[0]卷积层进行通道数的调整，得到inner_lateral1。然后将top_down_layer2上
                  采样至inner_lateral1的大小，再将其与inner_lateral1相加，得到融合后的特征层top_down_layer1。
                6、对于layer1特征层，将top_down_layer1作为该层对应的预测特征层self.layer_blocks[0]的输入，得到out_layer1。
            最后，输出的tensor_fpn为[out_layer1, out_layer2, out_layer3]，即分别对应融合后的layer1、layer2和layer3
            三个特征层的预测特征矩阵。

            :param x: OrderDict[Tensor]: feature maps
            :return: OrderDict[Tensor],返回的特征图（feature maps）的顺序是从分辨率最高的开始，
                     逐步下采样（resolution decreases）的顺序排列的。
        """
        names = list(x.keys())
        x = list(x.values())

        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
        # 下面是最后一个feature map经过FPN后的计算结果                                                        #
        # # 计算x经过最后layer4经FPN调整out_channels后的结果
        last_inner = self.get_result_from_inner_blocks(x[-1], -1)
        # results保存每个feature map经过FPN后的结果
        results = []
        results.append(self.get_result_from_layer_blocks(last_inner, -1))
        # 剩余层的计算过程，从后向前，因为越往后feature map尺度越小，分辨率越小
        # 对于除了最后一层，前面一层都要融合后一层的信息, 因此从后向前
        for idx in range(len(x) - 2, -1, -1):
            # 对于当前层，先对其通道进行调整
            inner_lateral = self.get_result_from_inner_blocks(x[idx], idx)
            # 查看feature map的分辨率
            feat_shape = inner_lateral.shape[-2:]
            # 然后将上一层的feature map进行上采样，调整到与当前层尺度相同
            inner_top_down = F.interpolate(last_inner, size=feat_shape, mode="nearest")
            # 然后进行融合
            last_inner = inner_lateral + inner_top_down
            # 然后得到作为预测的特征层
            results.insert(0, self.get_result_from_layer_blocks(last_inner, idx))

        # 将最后一层的预测特征层的基础上经过最大池化再生成一个feature map
        if self.extra_block is not None:
            results, names = self.extra_block(results, x, names)

        out = OrderedDict([(k, v) for k, v in zip(names, results)])
        return out

class BackboneWithFPN(nn.Module):
    """
    在model的上面加上一个FPN
    使用IntermediaLayerGetter模块（torchvision.models._utils.IntermediateLayerGetter）去提取返回return layers所指定的特征图
    Arguments:
        backbone: 已经经过create_feature_extractor，指定return layers的backbone
        return_layers: Dict[name, new_name]: FPN所采用的那些层，eg:
                        return_layers = {"features.6": "0",   # stride 8
                                         "features.12": "1",  # stride 16
                                         "features.16": "2"}  # stride 32

        in_channels_list: List[int], 每个layer的channel
        out_channels: FPN的channel
        extra_blocks: extra_blocks 是指在构建 Feature Pyramid Network (FPN) 时，除了基础模型（backbone）外，需要添加的
                      额外的上采样模块。在 torchvision 中，这些额外的模块被称为 Extra FPN Blocks，它们用于将来自底层 feature maps
                      的信息提取到更高层次的 feature maps 中，以实现更好的目标检测性能。通常，这些额外模块可以是卷积层或反卷积层等。

    """

    def __init__(self,
                 backbone: nn.Module,
                 return_layers=None,
                 in_channels_list=None,
                 out_channels=256,
                 extra_blocks=None,
                 re_getter=True):
        super(BackboneWithFPN, self).__init__()

        if extra_blocks is None:
            extra_blocks = LastLevelMaxPool()
        """
        当 re_getter 参数设置为 True 时，我们需要为 FPN 创建一个新的 IntermediateLayerGetter 对象来从 backbone 中提取中间层特征图。
        这是因为有些 FPN 模型需要返回 backbone 的多个中间层的特征图，而这些特征图不一定连续，可能是隔了几层才能获得的。因此，需要用
        IntermediateLayerGetter 来动态地提取这些中间层特征图，并传递给FPN模型使用。
        而当 re_getter 参数设置为 False 时，我们直接将 backbone 传递给 FPN，表示 FPN 不需要重新获取 backbone 的中间层特征图，
        而是直接使用backbone自带的中间层特征图。这种情况一般用于当backbone的输出层与 FPN 所需要的输出层完全一致时。

        """
        # regetter就是对backbone进行重构，前面已经使用create_feature_extractor进行重构了，这里不需要再次重构
        if re_getter is True:
            assert return_layers is not None
            self.body = IntermediateLayerGetter(backbone, return_layers=return_layers)
        else:
            self.body = backbone

        self.fpn = FeaturePyramidNetwork(in_channels_list=in_channels_list,
                                         out_channels=out_channels,
                                         extra_block=extra_blocks)

        self.out_channels = out_channels

    def forward(self, x):
        # 先x经过backbone
        x = self.body(x)
        # 然后经过FPN输出对应的预测特征层
        x = self.fpn(x)
        return x

class LastLevelMaxPool(nn.Module):
    """
    在最后一层feature map上进行一次最大池化
    输入x是Dict feature maps, 将x的最后一个feature map进行一次最大池化
    """
    def forward(self, x: List[Tensor], y: List[Tensor], names: List[str]) -> Tuple[List[Tensor], List[str]]:
        names.append("pool")
        x.append(F.max_pool2d(x[-1], 1, 2, 0))
        return x, names