from transfo import *
from contour import *
from testing import *
from constant import *

PROCESSING_DIR = "/Users/nicolasbancel/git/perso/mamie/project/images/processing/canny_tutorial/"

if __name__ == "__main__":

    white_rectangles = True
    add_margin = True
    thresholding = False
    canny_detection = True

    original = load_original()
    if white_rectangles:
        original = whiten_edges(original)
    if add_margin:
        original = add_borders(original)

    img_grey = grey_original(original)
    img_blur = cv2.blur(img_grey, (3, 3))

    if thresholding:
        img_blur = cv2.adaptiveThreshold(
            img_grey,
            255,
            cv2.ADAPTIVE_THRESH_MEAN_C,
            cv2.THRESH_BINARY,
            blockSize=3,
            C=2,
        )

    detected_edges = cv2.Canny(img_blur, 12, 12 * 3, 3)
    # cv2.imwrite(f"{PROCESSING_DIR}canny_edges_lowthresh_{val}_{args.input}", detected_edges)

    ### CONTOURS SECTION ###

    retrieval_mode = cv2.RETR_EXTERNAL
    retrieval_method = cv2.CHAIN_APPROX_NONE
    num_contours = 10

    contours, hierarchy = cv2.findContours(detected_edges, retrieval_mode, retrieval_method)
    original_with_contours = original.copy()
    main_contours = sorted(contours, key=cv2.contourArea, reverse=True)[:num_contours]
    cv2.drawContours(original_with_contours, main_contours, -1, (0, 255, 0), 30)
    print("Number of contours identified: ", len(contours))
    show("Original with contours", original_with_contours)

    ### END OF CONTOURS SECTION ###

    contours, _ = find_contours(source=detected_edges)
    original_with_main_contours, PictureContours, key = draw_main_contours(
        original,
        contours,
        num_contours=6,
        contour_size=40,
        contours_color=(0, 255, 0),
        only_rectangles=False,
        show_image=True,
    )


T = int(input())
for a in range(0,T):
    n = int(input())
    source = input().split(' ')
    sum1=sum2=0
    for i in range(0,n):
        if i%2==0:
            sum2+=int(source[i])
        elif i%2==1:
            sum1+=int(source[i])
    print(max(sum1,sum2))


import logging
from celery import Celery, Task, group
from ingester import config as cfg
from ingester.aws import download_file
from ingester.db import load_review
from ingester.utils import tmp_dir

logger = logging.getLogger(__name__)

app = Celery("tasks", broker=cfg.CELERY.BrokerUrl, backend=cfg.CELERY.ResultBackend)

app.conf.update(
    result_expires=10,
    beat_schedule={
    })

class BaseTask(Task):
    abstract = True

    def __call__(self, *args, **kwargs):
        super(BaseTask, self).__call__(*args, **kwargs)
        logger.info(f'Ingestion started')

    def on_success(self, retval, task_id, args, kwargs):
        logger.info(f'Ingestion succeeded')

    def on_failure(self, exc, task_id, args, kwargs, einfo):
        logger.info(f'Ingestion failed')

@app.task(name='ingester.tasks.task_dispacher', base=BaseTask, bind=True)
def task_dispacher(self, keys: list) -> None:
    group(
        [
            ingest_data_to_db.si(key)
            for key in keys
        ]
    )()

@app.task(name='ingester.tasks.ingest_data_to_db', base=BaseTask, bind=True)
def ingest_data_to_db(self, key: str) -> None:
    with tmp_dir() as working_dir:
        filepath = download_file(key, working_dir)
        load_review(filepath)


import os
import json
import time
from PIL import Image
from typing import Dict
from collections import Counter
import random
# import cv2
import obonet
import networkx
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
import matplotlib.pyplot as plt
import matplotlib.patches as mpatch
from Bio import SeqIO
from pyvis.network import Network

CAFA5 = "/Users/harrietobrien/Desktop/CAFA5"
TRAIN = "{home}/Train".format(home=CAFA5)

class CFG:
    gobasic = "{path}/go-basic.obo".format(path=TRAIN)
    sequences = "{path}/train_sequences.fasta".format(path=TRAIN)
    terms = "{path}/train_terms.tsv".format(path=TRAIN)
    taxonomy = "{path}/train_taxonomy.tsv".format(path=TRAIN)
    ia = "{path}/IA.txt".format(path=CAFA5)

class color:
    PURPLE = '\033[95m'
    CYAN = '\033[96m'
    DARKCYAN = '\033[36m'
    BLUE = '\033[94m'
    GREEN = '\033[92m'
    YELLOW = '\033[93m'
    RED = '\033[91m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'
    END = '\033[0m'

# obonet package to load this file
graph = obonet.read_obo(CFG.gobasic)
print(f"Number of nodes: {len(graph)}")
print(f"Number of edges: {graph.number_of_edges()}")
term = "GO:0034655"
# nucleobase-containing compound catabolic process node properties
print(graph.nodes[term])
print(type(graph))  # --> <class 'networkx.classes.multidigraph.MultiDiGraph'>
print(type(graph.nodes[term]))  # --> <class 'dict'>
# plt.plot_dag(graph, term, radius=1)
# plot_dag(graph, term, radius=1000)

# analyze  protein sequences from sequences file with Biopython package
print("Sequence example:\n\n", next(iter(SeqIO.parse(CFG.sequences, "fasta"))))
#  count the number of sequences
sequences = SeqIO.parse(CFG.sequences, "fasta")
num_sequences = sum(1 for seq in sequences)
print("Number of sequences:", num_sequences)

# plot the length distribution of the protein sequences
sequences = SeqIO.parse(CFG.sequences, "fasta")
# get the length of each sequence
lengths = [len(seq) for seq in sequences]
fig = px.histogram(x=lengths, nbins=1000, color_discrete_sequence=['goldenrod'])
fig.update_layout(
    title={
        'text': "Distribution of protein sequence lengths",
        'y': 0.95,
        'x': 0.5,
        'xanchor': 'center',
        'yanchor': 'top'
    },
    xaxis_title="Sequence length", yaxis_title="Count"
)
fig.show()
np.percentile(lengths, 99)

# calculate the amino acid composition of each protein sequence
records = SeqIO.parse(CFG.sequences, "fasta")
# create a list of all amino acids in the sequences
aa_list = [aa for record in records for aa in record.seq]
# count the frequency of each amino acid
aa_count = Counter(aa_list)
fig = px.bar(
    x=list(aa_count.values()), y=list(aa_count.keys()),
    color_discrete_sequence=['darkslateblue'],
    orientation='h', height=700
)
fig.update_layout(
    title={
        'text': "Amino Acid Composition",
        'y': 0.95,
        'x': 0.5,
        'xanchor': 'center',
        'yanchor': 'top'
    },
    xaxis_title="Frequency", yaxis_title="Amino Acid"
)
fig.show()
# Load the train terms dataframe
train_terms = pd.read_csv(CFG.terms, sep="\t")
train_terms.head()
train_terms.describe()
# TODO: Join train_terms_df.EntryID on train_taxonomy_df.EntryID
# Information accretion
limit = 10

with open(CFG.ia) as f:
    ia_weights = [x.replace("\n", "").split("\t") for x in f.readlines()]

ia_weights[:limit]


import sys
sys.path.insert(0,'C:/Users/Hp/Desktop/Data Analyst/mlProject/src')
from dataclasses import dataclass
import numpy as np
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder,StandardScaler
from sklearn.pipeline import Pipeline

from exception import CustomException
from logger import logging
import os

from utils import save_object

@dataclass
class DataTransformationConfig:
    preprocessor_obj = os.path.join('artifact',"Preprocessor.pkl")

class DataTransformation:
    def __init__(self):
        self.data_transformation_config = DataTransformationConfig()

    def get_data_transformer(self):
        try:
            numerical_columns = ["reading_score","writing_score"]
            categorical_columns = ["gender","race_ethnicity","lunch","parental_level_of_education","test_preparation_course"]

            num_pipeline = Pipeline(
                steps=[
                    ("imputer",SimpleImputer(strategy="median")),
                    ("scaler",StandardScaler(with_mean=False))
                ]
            )

            cat_pipeline = Pipeline(
                steps=[
                    ("imputer",SimpleImputer(strategy="most_frequent")),
                    ("one_hot_encoder",OneHotEncoder()),
                    ("scaler",StandardScaler(with_mean=False))
                ]
            )

            logging.info("Numerical columns standard scaling completed")
            logging.info("Categorical columns encoding completed")

            preprocessor = ColumnTransformer(
                [
                    ("num_pipeline",num_pipeline,numerical_columns),
                    ("cat_pipeline",cat_pipeline,categorical_columns)
                ]
            )

            return preprocessor

        except Exception as e:
            raise CustomException(e,sys)

    def initiate_data_transformation(self,train_path,test_path):
        try:
            train_df=pd.read_csv(train_path)
            test_df = pd.read_csv(test_path)

            logging.info("Read train and test data completed")

            logging.info("Obtaining preprocessing data")

            preprocessing_obj = self.get_data_transformer()
            target_column="math_score"
            numerical_columns = ["reading_score","writing_score"]

            input_feature_train = train_df.drop(columns=[target_column],axis=1)
            target_feature_train = train_df[target_column]

            input_feature_test = test_df.drop(columns=[target_column],axis=1)
            target_feature_test = test_df[target_column]

            logging.info("Applying preprocessing on training and testing dataframe")

            input_feature_train_arr=preprocessing_obj.fit_transform(input_feature_train)
            input_feature_test_arr=preprocessing_obj.transform(input_feature_test)

            train_arr = np.c_[
                input_feature_train_arr, np.array(target_feature_train)
            ]
            test_arr = np.c_[input_feature_test_arr, np.array(target_feature_test)]

            logging.info(f"Saved preprocessing object.")

            save_object(

                file_path=self.data_transformation_config.preprocessor_obj,
                obj=preprocessing_obj

            )

            return (
                train_arr,
                test_arr,
                self.data_transformation_config.preprocessor_obj,
            )

        except Exception as e:
            raise CustomException(e,sys)


import errors.e as er
import libs.commands as c
import os

def run(args):
    if(len(args) > 2):
        er.TooManyArgsError(args[0])
    elif (len(args) == 2):
        #os.system("cd " + args[1])
        os.chdir(args[1])
    else:
        er.TooLittleArgsError(args[0])


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import roc_curve, auc, precision_recall_curve, f1_score, confusion_matrix
from sklearn.metrics import average_precision_score, roc_auc_score
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import RandomizedSearchCV, GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.neural_network import MLPClassifier
from sklearn import svm
import lightgbm as lgb
import shap
import warnings
warnings.filterwarnings('ignore')

def shap_plot(model, data, center, modelname):
    if modelname == 'RF' or modelname == 'LGBM':
        explainer = shap.TreeExplainer(model)
        shap_values = explainer.shap_values(data, approximate=False, check_additivity=False)
    elif modelname == 'LR':
        masker = shap.maskers.Independent(data=data)
        explainer = shap.LinearExplainer(model, masker=masker)
        shap_values = explainer.shap_values(data)
    elif modelname == 'SVM' or modelname == 'MLP':
        explainer = shap.KernelExplainer(model.predict_proba, data)
        shap_values = explainer.shap_values(data)

    if isinstance(shap_values, list):
        shap.summary_plot(shap_values[1], data, max_display=10, show=False, plot_size=(12, 8))
    elif isinstance(shap_values, np.ndarray):
        shap.summary_plot(shap_values, data, max_display=10, show=False, plot_size=(12, 8))

    plt.savefig('plots/SHAP_{}_{}.png'.format(center, modelname))
    plt.close()

def plot_aucs(label, score, name):
    sns.set_style('whitegrid')
    fig, axs = plt.subplots(1, 2, figsize=(10.5, 4.5))
    axs = axs.ravel()

    precision, recall, _ = precision_recall_curve(label, score, pos_label=1)
    auprc = auc(recall, precision)
    fpr, tpr, _ = roc_curve(label, score, pos_label=1)
    auroc = auc(fpr, tpr)

    axs[0].plot(fpr, tpr, c='b', lw=2, label='AUROC: {:.3f}'.format(auroc))
    axs[0].set_xlabel('fpr', fontsize=15)
    axs[0].set_ylabel('tpr', fontsize=15)
    axs[0].plot([0, 1], [0, 1], linestyle='dashed')
    axs[0].set_xlim([0, 1.05])
    axs[0].set_ylim([0, 1.05])
    axs[0].legend()

    axs[1].plot(recall, precision, c='b', lw=2,
                label='AUPRC: {:.3f}'.format(auprc))
    axs[1].plot([0, 1], [np.mean(label), np.mean(label)], linestyle='dashed')
    axs[1].set_xlim([0, 1.05])
    axs[1].set_ylim([0, 1.05])
    axs[1].legend()
    axs[1].set_xlabel('recall', fontsize=15)
    axs[1].set_ylabel('precision', fontsize=15)

    plt.tight_layout()
    plt.savefig('plots/{}.png'.format(name), dpi=300)
    plt.close()

def plot_aucs_withUncertainty(data, name):
    labels = []
    scores = []
    aucs = []
    precisions, recalls, fprs, tprs, auprcs, aurocs = [], [], [], [], [], []
    mean_fpr = np.linspace(0, 1, 100)
    mean_recall = np.linspace(0, 1, 100)
    for j in range(len(data[0])):
        label = data[0][j].tolist()
        score = data[1][j]
        labels.extend(label)
        scores.extend(score)
        precision, recall, _ = precision_recall_curve(label, score, pos_label=1)
        precision, recall = precision[::-1], recall[::-1]
        auprc = auc(recall, precision)
        interp_precision = np.interp(mean_recall, recall, precision)
        precisions.append(interp_precision)
        auprcs.append(auprc)
        fpr, tpr, _ = roc_curve(label, score, pos_label=1)
        auroc = auc(fpr, tpr)
        interp_tpr = np.interp(mean_fpr, fpr, tpr)
        interp_tpr[0] = 0.0
        tprs.append(interp_tpr)
        aucs.append(auroc)
    mean_tpr = np.mean(tprs, axis=0)
    std_tpr = np.std(tprs, axis=0)
    tprs_upper = np.minimum(mean_tpr + std_tpr, 1)
    tprs_lower = np.maximum(mean_tpr - std_tpr, 0)
    precisions, recalls, _ = precision_recall_curve(labels, scores)
    auprc = auc(recalls, precisions)
    std_auprc = np.std(auprcs)
    std_precision = np.std(precisions, axis=0)
    fprs, tprs, _ = roc_curve(labels, scores, pos_label=1)
    auroc = auc(fprs, tprs)
    std_auroc = np.std(aucs)

    plt.figure(figsize=(10.5, 4.5))
    plt.subplot(121)
    plt.plot(mean_fpr, mean_tpr, color='r',
             label='AUROC {:.3f}'.format(auroc),
             lw=2, alpha=.8)
    plt.fill_between(mean_fpr, tprs_lower, tprs_upper, color='r', alpha=0.3, )
    plt.xlim([0, 1])
    plt.ylim([0, 1.05])
    plt.legend()
    plt.ylabel('tpr', fontsize=15)
    plt.xlabel('fpr', fontsize=15)
    plt.title('ROC', fontsize=15)
    plt.subplot(122)
    plt.plot(recalls, precisions, lw=2, c='r',
             label='AUPRC {:.3f}'.format(auprc))
    plt.fill_between(recalls, precisions + std_precision,
                     precisions - std_precision, alpha=0.3, linewidth=0, color='r')
    plt.plot([0, 1], [np.mean(labels), np.mean(labels)], color='navy', lw=2, linestyle='--')
    plt.xlabel('recall', fontsize=15)
    plt.ylabel('precision', fontsize=15)
    plt.xlim([0, 1])
    plt.ylim([0, 1.05])
    plt.legend()
    plt.title('PRC', fontsize=15)
    plt.savefig('plots/{}.png'.format(name), dpi=300)
    plt.close()
    return auprc, auroc, std_auprc, std_auroc

def get_label(data_day, daytime):
    data_day['MODS'] = data_day[['cons05.resp', 'cons05.cvs', 'cons05.cns',
          'cons05.ren', 'cons05.hep', 'cons05.hem']].sum(1)
    data_day['MODS'] = (data_day['MODS']>=2).astype(int)
    patients = []
    nb_pid = 0
    for pid, patient in data_day.groupby('sample.id'):
        nb_pid += 1
        if daytime in patient['daytime'].tolist() and patient[patient['daytime'] == daytime]['MODS'].values[0] == 1:
                patient['label_MODS_day{}'.format(daytime)] = 1
        if patient['death.delay'].values[0] <= daytime:
            patient.loc[:, 'label_death_day{}'.format(daytime)] = 1
        patients.append(patient)

    patients = pd.concat(patients)
    patients_bc = patients[patients['daytime'] == 0]
    nb_pid_bc = len(patients_bc)
    patients_bc['label'] = (patients_bc[['label_MODS_day{}'.format(daytime),
                                         'label_death_day{}'.format(daytime)]].sum(1)==0).astype(int)

    patients_bc_MODS = patients_bc[patients_bc['MODS'] == 1]
    nb_pid_bc_MODS = len(patients_bc_MODS)
    return patients_bc_MODS, nb_pid, nb_pid_bc, nb_pid_bc_MODS

def metrics_80recall(model, test, label, score):
    precisions, recalls, thresholds = precision_recall_curve(label, score)
    threshold = thresholds[np.abs(recalls - 0.8).argmin()]
    pred = (model.predict_proba(test)[:, 1] >= threshold).astype(int).flatten()
    test_table = pd.DataFrame(columns=['true', 'pred'])
    test_table['true'] = list(label)
    test_table['pred'] = list(pred)
    tn, fp, fn, tp = confusion_matrix(test_table['true'], test_table['pred']).ravel()
    precision = tp / (tp + fp)
    specificity = tn / (tn + fp)
    f1 = f1_score(test_table['true'], test_table['pred'])
    npv = tn / (tn + fn)
    accuracy = (tp + tn) / (tp + fp + tn + fn)
    recall = tp / (tp + fn)
    return [precision,  specificity, f1, npv, accuracy, recall]

def RF_grid(data, label, scoring):
    grid = {"n_estimators": np.arange(100, 2000, 200),
           'max_depth':[10,20,30,40,50,60],
           'max_leaf_nodes': [50, 100, 200],
           'min_samples_leaf':[1,2,4]}
    rf = RandomForestClassifier()
    rf_grid = RandomizedSearchCV(rf, grid, n_iter=50, cv=5, n_jobs=-1, scoring=scoring)
    rf_grid.fit(data, label)
    return rf_grid

def MLP_grid(data, label, scoring):
    grid = {
        'hidden_layer_sizes': [(25, 50, 25), (25, 50),
                               (25, 25), (50, 50),
                               (50, 100), (50, 50, 50),
                              (50, 100, 50), ],
        'activation': ['tanh', 'relu'],
        'solver': ['adam'],
        'alpha': [0.0001, 0.00001, 0.001],
        'learning_rate': ['constant', 'adaptive'],
        'learning_rate_init':[0.001, 0.0001],
        'max_iter':[500, 1000, 5000, 10000]
    }
    mlp = MLPClassifier()
    mlp_grid = RandomizedSearchCV(mlp, grid, n_iter=50, cv=5, n_jobs=-1, scoring=scoring)
    mlp_grid.fit(data, label)
    return mlp_grid

def SVM_grid(data, label, scoring):
    grid = {
        {"kernel": ["rbf"], "gamma": [1e-2, 1e-3, 1e-4], 'C':np.logspace(-4,4,15)},
        {"kernel": ["linear"], 'C':np.logspace(-4,4,15)},
        }
    model = svm.SVC(probability=True)
    svm_grid = RandomizedSearchCV(model, grid, n_iter=50, cv=5, n_jobs=-1, scoring=scoring)
    svm_grid.fit(data, label)
    return svm_grid

def LR_grid(data, label, scoring):
    clf = LogisticRegression(max_iter=15000)
    grid ={'penalty': ["l1",  'l2'],
           'C':np.logspace(-4,4,20),
           'solver':['lbfgs’', 'liblinear']}
    lr_grid = GridSearchCV(clf, grid, n_jobs=-1, cv=5, scoring=scoring)
    lr_grid.fit(data, label)
    return lr_grid

def LGBM_grid(data, label, scoring):
    clf = lgb.LGBMClassifier(
        random_state=42,
        objective='binary',
        is_unbalance=True
    )
    grid = {
        'learning_rate':[0.01, 0.005, 0.001],
        'boosting_type': ["gbdt", "dart"],
        'n_estimators': np.arange(100, 2000, 200),
        'max_depth': [10, 20, 30, 40, 50, 60],
        'subsample': [0.8, 0.9, 1]
    }
    gbm_grid = algorithm_pipeline(data, label, clf, grid, scoring)
    return gbm_grid

def algorithm_pipeline(train_x, train_y,
                model, param_grid, scoring):
    rs = RandomizedSearchCV(
        estimator=model,
        param_distributions=param_grid,
        n_iter=50,
        cv=5,
        n_jobs=-1,
        scoring=scoring
    )
    fitted_CV = rs.fit(train_x, train_y)
    return fitted_CV

def cross_validation(train_list, val_list, test_list, features_selected, features_to_scale, model):
    predictions_val = []
    labels_val = []
    predictions_test = []
    labels_test = []
    models = []
    scoring = 'roc_auc'
    scaler = StandardScaler()
    for i in range(len(train_list)):

        X_train = train_list[i][features_selected]
        X_train[features_to_scale] = scaler.fit_transform(X_train[features_to_scale])
        X_train[features_to_scale] = X_train[features_to_scale].fillna(0)
        y_train = train_list[i]['label']

        X_val = val_list[i][features_selected]
        X_val[features_to_scale] = scaler.transform(X_val[features_to_scale])
        X_val[features_to_scale] = X_val[features_to_scale].fillna(0)
        y_val = val_list[i]['label']

        X_test = test_list[i][features_selected]
        X_test[features_to_scale] = scaler.transform(X_test[features_to_scale])
        X_test[features_to_scale] = X_test[features_to_scale].fillna(0)
        y_test = test_list[i]['label']

        fitted_CV = model(X_train, y_train, scoring)
        pred_val = fitted_CV.best_estimator_.predict_proba(X_val)[:, 1]
        pred_test = fitted_CV.best_estimator_.predict_proba(X_test)[:, 1]

        predictions_val.extend(list(pred_val))
        labels_val.extend(list(y_val))
        predictions_test.extend(list(pred_test))
        labels_test.extend(list(y_test))
        models.append(fitted_CV)

    auprc_val = average_precision_score(labels_val, predictions_val)
    auroc_val = roc_auc_score(labels_val, predictions_val)
    auprc_test = average_precision_score(labels_test, predictions_test)
    auroc_test = roc_auc_score(labels_test, predictions_test)

    return auprc_val, auroc_val, auprc_test, auroc_test, models, predictions_test, labels_test

def enrichment_test(From, To, test_col, alpha=0.05):

    # test for enrichment/depletion in From set compared to To set.
    counts = {}
    draw_num = To.shape[0]
    # 100 random samplings
    instances = From[test_col].unique()
    num_test = instances.shape[0] * 100
    correction_num = From[test_col].unique().shape[0]

    for instance in instances:
        counts[instance] = []

    for k in range(num_test):
        draw = From.sample(draw_num)[test_col].value_counts() / draw_num
        for instance in instances:
            if instance in draw.index:
                counts[instance].append((draw)[instance])
            else:
                counts[instance].append(0)

    ratios_to = To[test_col].value_counts() / len(To)
    ratios_from = From[test_col].value_counts() / len(From)

    base = {}
    report = pd.DataFrame(columns=['Group', 'Instance', 'From', 'To', 'Type'])
    i = 1

    for instance in instances:
        if instance in ratios_to.index:
            base[instance] = 1 if (ratios_to)[instance] >= (ratios_from)[instance] else 0
        else:
            ratios_to[instance] = 0
            base[instance] = 0

        if base[instance] == 1 and np.sum(np.array(counts[instance]) >= (ratios_to)[instance]) <= (
                num_test * alpha / correction_num):
            print('Enrichment of {} in FP from {:.3f} to {:.3f}.'.format(
                instance, (ratios_from)[instance], (ratios_to)[instance]))
            report.loc[i] = [test_col, instance, (ratios_from)[instance],
                             (ratios_to)[instance], 'Enrichment']
            i += 1

        if base[instance] == 0 and np.sum(np.array(counts[instance]) <= (ratios_to)[instance]) <= (
                num_test * alpha / correction_num):
            print('Depletion of {} in FP from {:.3f} to {:.3f}.'.format(
                instance, (ratios_from)[instance], (ratios_to)[instance]))
            report.loc[i] = [test_col, instance, (ratios_from)[instance],
                             (ratios_to)[instance], 'Depletion']
            i += 1

    return report


import json
from django.test import TestCase
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase

from pereval.serializers import *

class PerevalApiTestCase(APITestCase):
    def setUp(self) -> None:
        self.pereval_1 = Pereval.objects.create(
            user=PassUser.objects.create(
                email="Test1@mail.ru",
                lastname="Test1",
                firstname="Test1",
                surname="Test1",
                phone="8-001-001-01-01"
            ),
            beauty_title="ПЕРЕВАЛ1",
            title="ПЕРЕВАЛ1",
            other_titles="ПЕРЕВАЛ1",
            connect='',
            coords=Coords.objects.create(
                latitude=49.000001,
                longitude=86.000001,
                height=3001
            ),
            level=Level.objects.create(
                winter='',
                summer='',
                autumn='',
                spring=''
            )
        )
        self.image_1_1 = Images.objects.create(
            data="https://pereval.ru/pereval1-1.jpg",
            title="pereval1-1",
            pereval=self.pereval_1
        )
        self.image_1_2 = Images.objects.create(
            data="https://pereval.ru/pereval1-2.jpg",
            title="pereval1-2",
            pereval=self.pereval_1
        )

        self.pereval_2 = Pereval.objects.create(
            user=PassUser.objects.create(
                email="Test2@mail.ru",
                lastname="Test2",
                firstname="Test2",
                surname="Test2",
                phone="8-002-002-02-02"
            ),
            beauty_title="ПЕРЕВАЛ2",
            title="ПЕРЕВАЛ2",
            other_titles="ПЕРЕВАЛ2",
            connect='',
            coords=Coords.objects.create(
                latitude=49.000002,
                longitude=86.000002,
                height=3002),
            level=Level.objects.create(
                winter='',
                summer='',
                autumn='',
                spring=''
            )
        )
        self.image_2_1 = Images.objects.create(
            data="https://pereval.ru/pereval2-1.jpg",
            title="pereval2-1",
            pereval=self.pereval_2
        )
        self.image_2_2 = Images.objects.create(
            data="https://pereval.ru/pereval2-2.jpg",
            title="pereval2-2",
            pereval=self.pereval_2
        )

        self.pereval_3 = Pereval.objects.create(
            user=PassUser.objects.create(
                email="Test3@mail.ru",
                lastname="Test3",
                firstname="Test3",
                surname="Test3",
                phone="8-003-003-03-03"
            ),
            beauty_title="ПЕРЕВАЛ3",
            title="ПЕРЕВАЛ3",
            other_titles="ПЕРЕВАЛ3",
            connect='',
            coords=Coords.objects.create(
                latitude=49.000003,
                longitude=86.000003,
                height=3003),
            level=Level.objects.create(
                winter='',
                summer='',
                autumn='',
                spring=''
            ),
            status='pending'
        )
        self.image_3_1 = Images.objects.create(
            data="https://pereval.ru/pereval3-1.jpg",
            title="pereval3-1",
            pereval=self.pereval_3
        )
        self.image_3_2 = Images.objects.create(
            data="https://pereval.ru/pereval3-2.jpg",
            title="pereval3-2",
            pereval=self.pereval_3
        )

    def test_get(self):
        url = reverse('pereval-list')
        response = self.client.get(url)
        serializer_data = PerevalSerializer([self.pereval_1, self.pereval_2, self.pereval_3], many=True).data
        self.assertEqual(status.HTTP_200_OK, response.status_code)
        self.assertEqual(serializer_data, response.json())
        self.assertEqual(len(serializer_data), 3)

    def test_get_detail(self):
        url = reverse('pereval-detail', args=(self.pereval_1.id,))
        response = self.client.get(url)
        serializer_data = PerevalSerializer(self.pereval_1).data
        self.assertEqual(status.HTTP_200_OK, response.status_code)
        self.assertEqual(serializer_data, response.json())

    def test_create_and_user_reuse(self):
        url = reverse('pereval-list')
        data = {
            'user': {
                'email': 'Test1@mail.ru',
                'firstname': 'Test1',
                'lastname': 'Test1',
                'surname': 'Test1',
                'phone': '8-001-001-01-01'
            },
            'beauty_title': 'ПЕРЕВАЛ5',
            'title': 'ПЕРЕВАЛ5',
            'other_titles': 'ПЕРЕВАЛ5',
            'connect': '',
            'coords': {
                'latitude': 49.000005,
                'longitude': 86.000005,
                'height': 3005
            },
            'level': {
                'winter': '1A',
                'summer': '',
                'autumn': '1A',
                'spring': ''
            },
            'images': [
                {
                    'data': 'https://pereval.ru/pereval5-1.jpg',
                    'title': 'pereval5-1'
                },
                {
                    'data': 'https://pereval.ru/pereval5-2.jpg',
                    'title': 'pereval5-2'
                }
            ]
        }
        json_data = json.dumps(data)
        response = self.client.post(url, data=json_data, content_type='application/json')
        self.assertEqual(status.HTTP_200_OK, response.status_code)
        self.assertEqual(4, Pereval.objects.all().count())
        self.assertEqual(3, PassUser.objects.all().count())

    def test_not_create(self):
        url = reverse('pereval-list')
        data = {
            'user': {
                'email': '',
                'firstname': '',
                'lastname': '',
                'surname': '',
                'phone': ''
            },
            'beauty_title': '',
            'title': '',
            'other_titles': '',
            'connect': '',
            'coords': {
                'latitude': 49.000000,
                'longitude': 86.000000,
                'height': 3000
            },
            'level': {
                'winter': '',
                'summer': '',
                'autumn': '',
                'spring': ''
            },
            'images': [
                {
                    'data': '',
                    'title': ''
                },
                {
                    'data': '',
                    'title': ''
                }
            ]
        }
        json_data = json.dumps(data)
        response = self.client.post(url, data=json_data, content_type='application/json')
        self.assertEqual(status.HTTP_200_OK, response.status_code)
        self.assertEqual(3, Pereval.objects.all().count())

    def test_update(self):
        url = reverse('pereval-detail', args=(self.pereval_1.id,))
        data = {
            'user': {
                'email': self.pereval_1.user.email,
                'firstname': self.pereval_1.user.firstname,
                'lastname': self.pereval_1.user.lastname,
                'surname': self.pereval_1.user.surname,
                'phone': self.pereval_1.user.phone
            },
            'beauty_title': self.pereval_1.beauty_title,
            'title': self.pereval_1.title,
            'other_titles': self.pereval_1.other_titles,
            'connect': 'Что-то соединяет',
            'coords': {
                'latitude': 49.444444,
                'longitude': 86.444444,
                'height': 3444
            },
            'level': {
                'winter': '1A',
                'summer': '1B',
                'autumn': '1C',
                'spring': '1D'
            },
            'images': [
                {
                    'data': 'https://pereval.ru/pereval1-1.jpg',
                    'title': 'pereval1-1'
                },
                {
                    'data': 'https://pereval.ru/pereval1-2.jpg',
                    'title': 'pereval1-2'
                }
            ],
            'status': 'pending'
        }
        json_data = json.dumps(data)
        response = self.client.patch(url, data=json_data, content_type='application/json')
        self.assertEqual(status.HTTP_200_OK, response.status_code)
        self.pereval_1.refresh_from_db()
        self.assertEqual(49.444444, self.pereval_1.coords.latitude)
        self.assertEqual(86.444444, self.pereval_1.coords.longitude)
        self.assertEqual(3444, self.pereval_1.coords.height)
        self.assertEqual('1A', self.pereval_1.level.winter)
        self.assertEqual('1B', self.pereval_1.level.summer)
        self.assertEqual('1C', self.pereval_1.level.autumn)
        self.assertEqual('1D', self.pereval_1.level.spring)
        self.assertEqual('pending', self.pereval_1.status)

    def test_update_not_status_new(self):
        url = reverse('pereval-detail', args=(self.pereval_3.id,))
        data = {
            'user': {
                'email': self.pereval_3.user.email,
                'firstname': self.pereval_3.user.firstname,
                'lastname': self.pereval_3.user.lastname,
                'surname': self.pereval_3.user.surname,
                'phone': self.pereval_3.user.phone
            },
            'beauty_title': self.pereval_3.beauty_title,
            'title': self.pereval_3.title,
            'other_titles': self.pereval_3.other_titles,
            'connect': '',
            'coords': {
                'latitude': 49.333333,
                'longitude': 86.333333,
                'height': 3333
            },
            'level': {
                'winter': '',
                'summer': '',
                'autumn': '',
                'spring': ''
            },
            'images': [
                {
                    'data': 'https://pereval.ru/pereval3-1.jpg',
                    'title': 'pereval3-1'
                },
                {
                    'data': 'https://pereval.ru/pereval3-2.jpg',
                    'title': 'pereval3-2'
                }
            ]
        }
        json_data = json.dumps(data)
        response = self.client.patch(url, data=json_data, content_type='application/json')
        self.assertEqual(status.HTTP_200_OK, response.status_code)
        self.pereval_1.refresh_from_db()
        self.assertEqual(49.000003, self.pereval_3.coords.latitude)
        self.assertEqual(86.000003, self.pereval_3.coords.longitude)
        self.assertEqual(3003, self.pereval_3.coords.height)

    def test_user_update(self):
        url = reverse('pereval-detail', args=(self.pereval_2.id,))
        data = {
            'user': {
                'email': 'email@mail.ru',
                'firstname': 'firstname',
                'lastname': 'lastname',
                'surname': 'surname',
                'phone': '8-888-888-88-88'
            },
            'beauty_title': 'ПЕРЕВАЛ2',
            'title': 'ПЕРЕВАЛ2',
            'other_titles': 'ПЕРЕВАЛ2',
            'connect': '',
            'coords': {
                'latitude': 49.000002,
                'longitude': 86.000002,
                'height': 3002
            },
            'level': {
                'winter': '',
                'summer': '',
                'autumn': '',
                'spring': ''
            },
            'images': [
                {
                    'data': 'https://pereval.ru/pereval2-1.jpg',
                    'title': 'pereval2-1'
                },
                {
                    'data': 'https://pereval.ru/pereval2-2.jpg',
                    'title': 'pereval2-2'
                }
            ]
        }
        json_data = json.dumps(data)
        response = self.client.patch(url, data=json_data, content_type='application/json')
        self.assertEqual(status.HTTP_200_OK, response.status_code)
        self.pereval_1.refresh_from_db()
        self.assertEqual('Test2@mail.ru', self.pereval_2.user.email)
        self.assertEqual('Test2', self.pereval_2.user.firstname)
        self.assertEqual('Test2', self.pereval_2.user.lastname)
        self.assertEqual('Test2', self.pereval_2.user.surname)
        self.assertEqual('8-002-002-02-02', self.pereval_2.user.phone)

class PerevalSerializerTestCase(TestCase):
    def setUp(self) -> None:
        self.pereval_1 = Pereval.objects.create(
            user=PassUser.objects.create(
                email="Test1@mail.ru",
                lastname="Test1",
                firstname="Test1",
                surname="Test1",
                phone="8-001-001-01-01"
            ),
            beauty_title="ПЕРЕВАЛ1",
            title="ПЕРЕВАЛ1",
            other_titles="ПЕРЕВАЛ1",
            connect='',
            coords=Coords.objects.create(
                latitude=49.000001,
                longitude=86.000001,
                height=3001
            ),
            level=Level.objects.create(
                winter='',
                summer='',
                autumn='',
                spring=''
            )
        )
        self.image_1_1 = Images.objects.create(
            data="https://pereval.ru/pereval1-1.jpg",
            title="pereval1-1",
            pereval=self.pereval_1
        )
        self.image_1_2 = Images.objects.create(
            data="https://pereval.ru/pereval1-2.jpg",
            title="pereval1-2",
            pereval=self.pereval_1
        )

        self.pereval_2 = Pereval.objects.create(
            user=PassUser.objects.create(
                email="Test2@mail.ru",
                lastname="Test2",
                firstname="Test2",
                surname="Test2",
                phone="8-002-002-02-02"
            ),
            beauty_title="ПЕРЕВАЛ2",
            title="ПЕРЕВАЛ2",
            other_titles="ПЕРЕВАЛ2", connect='',
            coords=Coords.objects.create(
                latitude=49.000002,
                longitude=86.000002,
                height=3002),
            level=Level.objects.create(
                winter='',
                summer='',
                autumn='',
                spring=''
            )
        )
        self.image_2_1 = Images.objects.create(
            data="https://pereval.ru/pereval2-1.jpg",
            title="pereval2-1",
            pereval=self.pereval_2
        )
        self.image_2_2 = Images.objects.create(
            data="https://pereval.ru/pereval2-2.jpg",
            title="pereval2-2",
            pereval=self.pereval_2
        )

    def test_ok(self):
        data = PerevalSerializer([self.pereval_1, self.pereval_2], many=True).data
        expected_data = [
            {
                'id': self.pereval_1.id,
                'user': {
                    'email': 'Test1@mail.ru',
                    'firstname': 'Test1',
                    'lastname': 'Test1',
                    'surname': 'Test1',
                    'phone': '8-001-001-01-01'
                },
                'beauty_title': 'ПЕРЕВАЛ1',
                'title': 'ПЕРЕВАЛ1',
                'other_titles': 'ПЕРЕВАЛ1',
                'connect': '',
                'coords': {
                    'latitude': 49.000001,
                    'longitude': 86.000001,
                    'height': 3001
                },
                'level': {
                    'winter': '',
                    'summer': '',
                    'autumn': '',
                    'spring': ''
                },
                'images': [
                    {
                        'data': 'https://pereval.ru/pereval1-1.jpg',
                        'title': 'pereval1-1'
                    },
                    {
                        'data': 'https://pereval.ru/pereval1-2.jpg',
                        'title': 'pereval1-2'
                    }
                ],
                'status': 'new'
            },
            {
                'id': self.pereval_2.id,
                'user': {
                    'email': 'Test2@mail.ru',
                    'firstname': 'Test2',
                    'lastname': 'Test2',
                    'surname': 'Test2',
                    'phone': '8-002-002-02-02'
                },
                'beauty_title': 'ПЕРЕВАЛ2',
                'title': 'ПЕРЕВАЛ2',
                'other_titles': 'ПЕРЕВАЛ2',
                'connect': '',
                'coords': {
                    'latitude': 49.000002,
                    'longitude': 86.000002,
                    'height': 3002
                },
                'level': {
                    'winter': '',
                    'summer': '',
                    'autumn': '',
                    'spring': ''
                },
                'images': [
                    {
                        'data': 'https://pereval.ru/pereval2-1.jpg',
                        'title': 'pereval2-1'
                    },
                    {
                        'data': 'https://pereval.ru/pereval2-2.jpg',
                        'title': 'pereval2-2'
                    }
                ],
                'status': 'new'
            }
        ]
        self.assertEqual(expected_data, data)


'''
This script continuously scans the 'New' posts on reddit.com/r/2007scape for submissions that are related
to the location of a dragon or lucky impling. If the submission's title or text contains at least one specific
keyword from a related set, an e-mail will be sent via gmail to the user specified in authentication.py.
Created by Dustin Kieler | /u/Chassy13 on July 3rd, 2018.
'''

import authentication
import configparser
import praw
import smtplib
from email.mime.text import MIMEText

# These keywords should all be lowercase only.
keywords = ['impling', 'dragon imp', 'drag imp', 'drg imp', 'dr imp', 'd imp', 'l imp', 'luck imp', 'lucky imp']

# Since we are just reading the New posts, we will create a Read-Only instance rather than
# using our own account or creating an account specifically for the bot.
# We do not need to use an infinite loop because the PRAW API will continuously grab the streamed submissions by itself.
def main():
    """Logs into Reddit in read-only mode and begins searching the 'New' posts of /r/2007scape
       for submissions related to dragon and lucky implings."""
    reddit = praw.Reddit(client_id="YOUR_APP_CLIENT_ID",
                         client_secret="YOUR_APP_CLIENT_SECRET",
                         user_agent="YOUR_UNIQUE_USER_AGENT_STRING")
    authentication.create_config()
    print("Now waiting patiently for implings...")
    for submission in reddit.subreddit('2007scape').stream.submissions():
        process_submission(submission)
    print("Submission loop has been terminated - restart needed.")

# We could compare the submission.created_utc time to time.time() if we wanted to only get posts that were created after
# we started running this script, but it's probably worth grabbing up to the last 25 submissions that may contain info
# about an impling because the submission may not have been seen yet.
def process_submission(submission):
    """Searches a submission title and text for keywords related to dragon and lucky implings.
       If a keyword is a match, calls to create and send an e-mail."""
    for keyword in keywords:
        if keyword in submission.title.lower() or keyword in submission.selftext.lower():
            email = create_email(submission.title, submission.selftext, submission.url)
            send_notification_email(email)

def send_notification_email(email):
    """Establishes the mail server and sends the e-mail to the address specified in the configuration."""
    server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
    server.ehlo()
    server.login(email['From'], get_credential('Key'))
    server.sendmail(email['From'], email['To'], email.as_string())
    server.quit()
    print("E-mail sent!")

def create_email(sub_title, sub_text, sub_url):
    """Creates an e-mail containing the impling post's title and text.
       The TO and FROM fields are the e-mail address in the configuration."""
    msg = MIMEText("Title: " + sub_title + "\n" + "Text: " + sub_text + "\n" + "URL: " + sub_url)
    address = get_credential('Address')
    msg['Subject'] = 'POTENTIAL IMPLING ALERT'
    msg['From'] = address
    msg['To'] = address
    return msg

# There is probably a cleaner way to do this in the future if we ever wanted to retrieve more properties,
# such as opening the configparser just one time and then passing along the property and/or tag to allow for more
# general use.
def get_credential(tag):
    """Searches the [CREDENTIALS] in the configuration for a specific property (tag)."""
    config = configparser.ConfigParser()
    config.read('auth.ini')
    return config['CREDENTIALS'][tag]

if __name__ == '__main__':
    main()


# 给定正整数 N ，我们按任何顺序（包括原始顺序）将数字重新排序，注意其前导数字不能为零。
#
# 如果我们可以通过上述方式得到 2 的幂，返回 true；否则，返回 false。

n = input().strip()
length = len(n)
n = sorted(n)
isOK = False
divv = (length-1) // 3
div = (length-1) % 3
begin = divv * 10
end = begin
if div == 0:
    end = begin + 4
elif div == 1:
    begin = begin + 4
    end = begin + 3
else:
    begin = begin + 7
    end = begin + 3
# print(begin, end)
for i in range(begin, end):
    t = pow(2, i)
    if n == sorted(str(t)):
        isOK = True
        break
print(str(isOK).lower())


#!/usr/bin/env python

## construct_dt_and_classify_one_sample_case1.py

##  This script shows the traditional usage of the
##  DecisionTree module.  By traditional I mean the usage up
##  to version 1.7.1.  The training data supplied through
##  the file `training.dat' is purely symbolic.  By the way,
##  this training data was produced by the script
##  generate_training_data_symbolic.py on the basis of the
##  parameters declared in the file `param_symbolic.txt'.

import DecisionTree
import sys

training_datafile = "training.dat"

dt = DecisionTree.DecisionTree( training_datafile = training_datafile,
                                entropy_threshold = 0.01,
                                max_depth_desired = 5,
                              )
dt.get_training_data()
#dt.calculate_first_order_probabilities_for_numeric_features()
dt.calculate_first_order_probabilities()
dt.calculate_class_priors()

#   UNCOMMENT THE FOLLOWING LINE if you would like to see the training
#   data that was read from the disk file:
#dt.show_training_data()

root_node = dt.construct_decision_tree_classifier()

#   UNCOMMENT THE FOLLOWING TWO LINES if you would like to see the decision
#   tree displayed in your terminal window:
print("\n\nThe Decision Tree:\n")
root_node.display_decision_tree("     ")

test_sample1 = [ 'exercising=never',
                 'smoking=heavy',
                 'fatIntake=heavy',
                 'videoAddiction=heavy']

test_sample2  = ['exercising=none',
                'smoking=heavy',
                'fatIntake=heavy',
                'videoAddiction=none']

# The rest of the script is for displaying the classification results:

classification = dt.classify(root_node, test_sample1)
solution_path = classification['solution_path']
del classification['solution_path']
which_classes = list( classification.keys() )
which_classes = sorted(which_classes, key=lambda x: classification[x], reverse=True)
print("\nClassification:\n")
print("     "  + str.ljust("class name", 30) + "probability")
print("     ----------                    -----------")
for which_class in which_classes:
    if which_class is not 'solution_path':
        print("     "  + str.ljust(which_class, 30) +  str(classification[which_class]))

print("\nSolution path in the decision tree: " + str(solution_path))
print("\nNumber of nodes created: " + str(root_node.how_many_nodes()))


def stat(arr):
    stat_sum = 0

    for i in arr:
        for j in arr:
            if i != j:
                stat_sum += start_link[i][j]

    return stat_sum

def collect(idx):
    global min_diff

    if idx == N:
        start = []
        link = []

        for bit in range(N):
            if bits[bit]:
                start.append(bit)
            else:
                link.append(bit)

        if start and link:
            res = abs(stat(start) - stat(link))

            if min_diff > res:
                min_diff = res

        return

    bits[idx] = 1
    collect(idx + 1)

    bits[idx] = 0
    collect(idx + 1)

N = int(input())
start_link = [list(map(int, input().split())) for _ in range(N)]
bits = [0] * N
min_diff = 980309

collect(0)
print(min_diff)


from PyQt5.Qt import *

class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("装饰器连接信号与槽的学习")
        self.resize(500, 500)

        self.setup_ui()

    def setup_ui(self):
        btn = QPushButton("测试按钮", self)
        btn.setObjectName("btn")
        btn.resize(200, 200)
        btn.move(100, 100)

        btn2 = QPushButton("测试按钮2", self)
        btn2.setObjectName("btn2")
        btn2.resize(200, 200)
        btn2.move(100, 300)

        QMetaObject.connectSlotsByName(self)
        # btn.clicked.connect(self.click)

    @pyqtSlot(bool)
    def on_btn_clicked(self, val):
        print("按钮被点击了", val)

    # self.btn.clicked[bool].connect(self.btn_clicked)
    # def btn_clicked(self):
    #     pass

if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)

    window = Window()
    window.show()

    sys.exit(app.exec_())


from flask import current_app

from archivy.helpers import get_elastic_client

def add_to_index(model):
    """
    Adds dataobj to given index. If object of given id already exists, it will be updated.

    Params:

    - **index** - String of the ES Index. Archivy uses `dataobj` by default.
    - **model** - Instance of `archivy.models.Dataobj`, the object you want to index.
    """
    es = get_elastic_client()
    if not es:
        return
    payload = {}
    for field in model.__searchable__:
        payload[field] = getattr(model, field)
    es.index(index=current_app.config["SEARCH_CONF"]["index_name"], id=model.id, body=payload)
    return True

def remove_from_index(dataobj_id):
    """Removes object of given id"""
    es = get_elastic_client()
    if not es:
        return
    es.delete(index=current_app.config["SEARCH_CONF"]["index_name"], id=dataobj_id)

def query_index(query):
    """Returns search results for your given query"""
    es = get_elastic_client()
    if not es:
        return []
    search = es.search(
        index=current_app.config["SEARCH_CONF"]["index_name"],
        body={
            "query": {
                "multi_match": {
                    "query": query,
                    "fields": ["*"],
                    "analyzer": "rebuilt_standard"
                }
            },
            "highlight": {
                "fragment_size": 0,
                "fields": {
                    "content": {
                        "pre_tags": "==",
                        "post_tags": "==",
                    }
                }
            }
        }
    )

    hits = []
    for hit in search["hits"]["hits"]:
        formatted_hit = {"id": hit["_id"], "title": hit["_source"]["title"]}
        if "highlight" in hit:
            formatted_hit["highlight"] = hit["highlight"]["content"]
        hits.append(formatted_hit)

    return hits


from cgi import print_environ
from cmath import log
import piheaan as heaan
import os
import numpy as np
import pandas as pd
import math
import json
import re
import natsort
import NB_log

params = heaan.ParameterPreset.FGb
context = heaan.make_context(params)
heaan.make_bootstrappable(context)
log_num_slot = heaan.get_log_full_slots(context)
num_slot = 1 << log_num_slot

final_ctxt = heaan.Ciphertext(context)

dec = heaan.Decryptor(context)
sk = heaan.SecretKey(context,"./key/secretkey.bin")

#####################################################################################
###############           Naive Bayesian classifier LEARNING          ###############
#####################################################################################
def data_encrypt(csv_file_path, ctxt_path, cell_col_max_list,context, keypack):
    try:
        os.makedirs(name=ctxt_path, mode=0o775, exist_ok=True)
    except Exception as e:
        print("[Error] Could not make train table directory: ", e)
        return
    enc = heaan.Encryptor(context)
    tmp = pd.read_csv(csv_file_path)
    col_name = list(tmp.columns)
    col_max_list = [int(str(cell_col_max).strip()) for cell_col_max in str(cell_col_max_list).split(',')]
    for j, c in enumerate(col_name):
        if 'label' in c:
            m = col_max_list[-1]
        else:
            m = col_max_list[int(c[-1])]
        for n in range(1,m+1):
            _add_one_zero_column(tmp,c,n)
    data = tmp.drop(columns=col_name, axis=1)

    for cname in data.columns:
        msg = heaan.Message(log_num_slot,0)
        for index in range(data[cname].size):
            msg[index]=data[cname][index]
        if ("Unnamed" not in cname):
            c = heaan.Ciphertext(context)
            enc.encrypt(msg,keypack,c)
            c.save(ctxt_path+cname+".ctxt")

    json_opend={}
    json_opend["num_rows"] = len(data)
    json_opend["bin_col_names"] = list(data.columns)
    json_opend["bin_num_lists"] = []

    for i , c in enumerate(col_name):
        if 'label' not in c:
            json_opend["bin_num_lists"].append(c + ":" + ','.join([str(j) for j in range(1,col_max_list[int(c[-1])]+1)]))
        else:
            json_opend["bin_num_lists"].append(c + ":" + ','.join([str(j) for j in range(1,col_max_list[-1]+1)]))

    with open(ctxt_path+"metadata.json", 'w') as f:
        f.write(json.dumps(json_opend, sort_keys=True, indent=4, separators=(',', ': ')))

def nb_learn(data_ctxt_path,eval, cell_col_max_list,alpha,context, keypack, model_ctxt_path):
    try:
        os.makedirs(name=model_ctxt_path, mode=0o775, exist_ok=True)
    except Exception as e:
        print("[Error] Could not make train table directory: ", e)
        return

    enc = heaan.Encryptor(context)
    col_max_list = [int(str(cell_col_max).strip()) for cell_col_max in str(cell_col_max_list).split(',')]

    with open(data_ctxt_path+"metadata.json",'r') as file:
            data_json_opend = json.load(file)
    data_cell_name_list = data_json_opend['bin_col_names']
    total_num = data_json_opend['num_rows']
    total_num_list = [total_num]*num_slot
    total_num_msg = heaan.Message(log_num_slot)
    for k in range(0,num_slot):
        total_num_msg[k] = total_num_list[k]
    # total_num_msg.set_data(total_num_list)
    total_num_ctxt = heaan.Ciphertext(context)
    enc.encrypt(total_num_msg, keypack, total_num_ctxt)
    total_num_ctxt.save(model_ctxt_path+'total_num.ctxt')

    data_cdict = load_ctxt(data_cell_name_list,data_ctxt_path,context)
    x_cols = []
    y_cols = []
    for i in data_cell_name_list:
        if 'X' in i:
            x_cols.append(i)
        else:
            y_cols.append(i)

    y_labels = col_max_list[-1]
    for y_label in range(1,y_labels+1):
        for i,p in enumerate(x_cols):
            # data_cdict[p].to_device()
            # data_cdict[str(y_label)+'Y_'].to_device()
            cname = str(y_label)+ "count"+p+"_"
            out_ctxt = heaan.Ciphertext(context)
            inv_ctxt = heaan.Ciphertext(context)
            rot_ctxt = heaan.Ciphertext(context)
            # out_ctxt.to_device()
            # inv_ctxt.to_device()
            # rot_ctxt.to_device()

            eval.mult(data_cdict[str(y_label)+'Y_'],data_cdict[p],out_ctxt)
            check_boot(out_ctxt,eval)

            rot_ctxt = rotate_sum(out_ctxt,eval)
            check_boot(rot_ctxt,eval)

            eval.add(rot_ctxt,alpha,rot_ctxt)

            rot_ctxt.save(model_ctxt_path+cname+".ctxt")
        yname = str(y_label)+'acountY_'
        rot_ctxt2 = heaan.Ciphertext(context)
        rot_ctxt2 = rotate_sum(data_cdict[str(y_label)+'Y_'],eval)
        check_boot(rot_ctxt2,eval)
        rot_ctxt2.save(model_ctxt_path+yname+".ctxt")

    fl = [re.sub('.ctxt','',i) for i in os.listdir(model_ctxt_path)]
    fl = natsort.natsorted(fl)

    data_cdict = load_ctxt(fl,model_ctxt_path,context)

    inverse_ctxt = heaan.Ciphertext(context)
    inverse_ctxt, inverse_index = make_inverse_ctxt(model_ctxt_path, eval, context,keypack,alpha,col_max_list)
    rotate_ctxt = make_rotate_ctxt(inverse_ctxt,inverse_index,eval,context,keypack)

    m_25_ctxt = make_25_ctxt(rotate_ctxt,eval)

    msg1 = [0]*num_slot
    for i in range(0,len(inverse_index)*25):
        msg1[i] = 1
    he_msg1 = heaan.Message(log_num_slot)
    for k in range(0,num_slot):
        he_msg1[k] = msg1[k]
    # he_msg1.set_data(data=msg1)
    # he_msg1.to_device()

    eval.mult(m_25_ctxt,he_msg1,m_25_ctxt)
    check_boot(m_25_ctxt,eval)
    find_log_ctxt = heaan.Ciphertext(context)

    find_log_ctxt = make_log_ctxt(m_25_ctxt, eval, context,keypack)

    final_result = heaan.Ciphertext(context)
    unit_size = 0
    for i in range(len(col_max_list)-1):
        unit_size+=int(col_max_list[i])

    unit_size+=1
    rs = [0]*32768
    st=0
    for _ in range(unit_size*col_max_list[-1]):
        rs[st]=1
        st +=25

    rs_msg = heaan.Message(log_num_slot)
    for k in range(0,num_slot):
        rs_msg[k] = rs[k]
    # rs_msg.set_data(rs)
    # rs_msg.to_device()

    eval.mult(find_log_ctxt, rs_msg, final_result)

    final_result = make_25_ctxt(final_result,eval)

    final_result.save(model_ctxt_path+"model.ctxt")

    flist = os.listdir(model_ctxt_path)
    for i in flist:
        if 'model' not in i:
            os.remove(model_ctxt_path+i)

#####################################################################################
###########################           INFERENCE          ############################
#####################################################################################
def inference_encrypt(csv_file_path, ctxt_path, cell_col_max_list,context, keypack):
    csv_file_path = str(csv_file_path)
    ctxt_path = str(ctxt_path)
    cell_col_max_list = str(cell_col_max_list)
    col_max_list = [int(str(cell_col_max).strip()) for cell_col_max in str(cell_col_max_list).split(',')]
    num_class = col_max_list[-1]
    try:
        os.makedirs(name=ctxt_path, mode=0o775, exist_ok=True)
    except Exception as e:
        print("[Error] Could not make train table directory: ", e)
        return
    enc = heaan.Encryptor(context)
    input_ = pd.read_csv(csv_file_path)
    ctxt_out = heaan.Ciphertext(context)
    unit_size = 0
    for i in range(len(col_max_list)-1):
        unit_size+=col_max_list[i]

    unit_size+=1
    total_size = unit_size * num_class*25

    ndata = num_slot//total_size
    required_ctxt = len(input_)//ndata if (len(input_) % ndata ==0) else len(input_)//ndata+1

    input_li = [[0]*num_slot for _ in range(required_ctxt)]
    cur_ctxt=0
    cur_idx=0
    cur_data=0
    for i in range(len(input_)):
        cur_item = input_.iloc[i].to_list()
        for k in range(num_class):
            input_li[int(cur_ctxt)][int(cur_idx+k*unit_size)*25]=1
        for j in range(len(col_max_list)-1):
            for k in range(num_class):
                input_li[int(cur_ctxt)][int(cur_idx+cur_item[j]+k*unit_size)*25]=1
            cur_idx+=col_max_list[j]
        cur_idx+=1
        cur_data+=1
        if (cur_data == ndata):
            cur_data=0
            cur_ctxt+=1
            cur_idx=0

    for i in range(required_ctxt):
        msg_=heaan.Message(log_num_slot)
        for j in range(0,num_slot):
            msg_[j] = input_li[i][j]
        # msg_.set_data(data = input_li[i])
        enc.encrypt(msg_,keypack,ctxt_out)
        ctxt_out.save(ctxt_path+"/input_"+str(i)+"_NB.ctxt")

def nb_predict(test_ctxt_path,model_ctxt_path, ycn, cell_col_max_list,key_file_path,eval):
    y_class_num = int(ycn)
    cell_col_max_list = str(cell_col_max_list)
    col_max_list = [int(str(cell_col_max).strip()) for cell_col_max in str(cell_col_max_list).split(',')]
    unit_size=0
    for i in range(len(col_max_list)-1):
        unit_size+=col_max_list[i]
    unit_size+=1

    keypack = heaan.KeyPack(context, key_file_path+"/")
    enc = heaan.Encryptor(context)

    model_ctxt = heaan.Ciphertext(context)
    model_ctxt.load(model_ctxt_path+"model.ctxt")
    feature_length = len(col_max_list)-1

    log_ = [-1/(np.log(1/32768)*(feature_length+1))]*num_slot
    logs = heaan.Ciphertext(context)
    logs_m = heaan.Message(log_num_slot)
    for j in range(0,num_slot):
            logs_m[j] = log_[j]
    enc.encrypt(logs_m, keypack, logs)
    # logs.to_device()

    # model_ctxt.to_device()
    check_boot(model_ctxt,eval)

    input_ctxt = heaan.Ciphertext(context)
    input_ctxt.load(test_ctxt_path+"input_0_NB.ctxt")
    # input_ctxt.to_device()
    check_boot(input_ctxt,eval)

    eval.mult(model_ctxt,input_ctxt,input_ctxt)
    check_boot(input_ctxt,eval)

    eval.mult(input_ctxt,logs,input_ctxt)
    check_boot(input_ctxt,eval)

    u_size = unit_size
    rot_size = u_size//2 if (u_size % 2 ==0) else u_size//2+1

    masku = [0]*num_slot
    maskd = [0]*num_slot

    num_iter = num_slot//(u_size*25)
    for i in range(num_iter):
        for j in range(u_size//2):
            maskd[i*u_size*25+j*25]=1
        for j in range(rot_size):
            masku[i*u_size*25+j*25]=1

    tmp_ctxt = heaan.Ciphertext(context)
    eval.left_rotate(input_ctxt,rot_size*25,tmp_ctxt)
    check_boot(tmp_ctxt,eval)

    masku_msg = heaan.Message(log_num_slot)
    for k in range(0,num_slot):
        masku_msg[k] = masku[k]
    # masku_msg.set_data(data = masku)
    # masku_msg.to_device()

    eval.mult(input_ctxt,masku_msg,input_ctxt)
    check_boot(input_ctxt,eval)

    maskd_msg = heaan.Message(log_num_slot)
    for o in range(0,num_slot):
        maskd_msg[o] = maskd[o]
    # maskd_msg.set_data(data = maskd)
    # maskd_msg.to_device()
    eval.mult(tmp_ctxt,maskd_msg,tmp_ctxt)
    check_boot(tmp_ctxt,eval)

    eval.add(input_ctxt,tmp_ctxt,input_ctxt)
    while(rot_size>1):
        rot_size = rot_size//2 if (rot_size % 2 ==0) else rot_size//2+1
        eval.left_rotate(input_ctxt,rot_size*25,tmp_ctxt)
        check_boot(tmp_ctxt,eval)
        eval.add(input_ctxt,tmp_ctxt,input_ctxt)

    input_ctxt_duplicate = heaan.Ciphertext(input_ctxt)
    # input_ctxt_duplicate.to_device()

    result_ctxt = heaan.Ciphertext(context)
    # result_ctxt.to_host()
    tmp_msg = [0]*num_slot

    for i in range(y_class_num):
        tmp_msg[i]=1

        tmp_ = heaan.Ciphertext(context)
        he_message=heaan.Message(log_num_slot)
        for k in range(0,log_num_slot):
            he_message[k] = 0

        enc.encrypt(he_message,keypack, tmp_)
        # tmp_.to_device()

        one_msg = heaan.Message(log_num_slot)
        msg=[0]*num_slot
        msg[i]=1
        for o in range(0,num_slot):
            one_msg[o] = msg[o]
        # one_msg.set_data(msg)
        # one_msg.to_device()
        if i ==0:
            eval.mult(input_ctxt, one_msg, result_ctxt)
            check_boot(result_ctxt,eval)
        else :
            eval.left_rotate(input_ctxt_duplicate,25*(unit_size)-1,input_ctxt_duplicate)
            check_boot(input_ctxt_duplicate,eval)

            eval.mult(input_ctxt_duplicate,one_msg,tmp_)
            check_boot(tmp_,eval)

            eval.add(tmp_, result_ctxt,result_ctxt)

    tmp_ctxt2 = heaan.Ciphertext(context)
    he_message2=heaan.Message(log_num_slot)
    for k in range(0,log_num_slot):
        he_message2[k] = tmp_msg[k]
    enc.encrypt(he_message2,keypack,tmp_ctxt2)
    # tmp_ctxt2.to_device()

    eval.mult(result_ctxt,tmp_ctxt2,result_ctxt)
    check_boot(result_ctxt,eval)

    final_result = heaan.Ciphertext(context)
    # final_result.to_device()
    if y_class_num != 2:
        final_result = findMaxPos(result_ctxt,context,keypack,log_num_slot,y_class_num,eval)

    elif y_class_num ==2 :
        result_duplicate = heaan.Ciphertext(result_ctxt)
        # result_duplicate.to_device()
        eval.left_rotate(result_duplicate,1,result_duplicate)
        check_boot(result_duplicate,eval)
        eval.mult(result_duplicate,-1,result_duplicate)
        check_boot(result_duplicate,eval)
        eval.add(result_duplicate,result_ctxt,result_ctxt)

        heaan.math.approx.sign(eval,result_ctxt,final_result)

    final_result.save(test_ctxt_path+"result.ctxt")

def decrypt_result(model_ctxt_path,ycn,key_file_path):
    dec = heaan.Decryptor(context)
    sk = heaan.SecretKey(context,key_file_path+"/secretkey.bin")
    y_class_num = int(ycn)

    result_ctxt= heaan.Ciphertext(context)
    result_msg = heaan.Message(log_num_slot)

    result_ctxt.load(model_ctxt_path+'result.ctxt')
    # result_ctxt.to_host()
    dec.decrypt(result_ctxt,sk,result_msg)

    if y_class_num==2:
        num = round(result_msg[0].real)
        if num ==1:
            return 1
        else :
            return 2
    else :
        num_list = []
        for i in range(y_class_num):
            num_list.append(round(result_msg[i].real))
        return (num_list.index(max(num_list)))+1

#####################################################################################
########################           INNER FUNCTIONS         ##########################
#####################################################################################
def make_rotate_ctxt(input_ctxt, index_dict,eval,context,keypack):
    enc = heaan.Encryptor(context)
    one_ = [0]*num_slot
    one_msg = heaan.Message(log_num_slot)
    for i in range(0,num_slot):
        one_msg[i] = one_[i]
    # one_msg.set_data(one_)

    return_ctxt = heaan.Ciphertext(context)
    enc.encrypt(one_msg,keypack,return_ctxt)

    duplicate_ctxt = heaan.Ciphertext(input_ctxt)
    # duplicate_ctxt.to_device()

    # input_ctxt.to_device()
    # return_ctxt.to_device()

    for i in range(len(index_dict)):
        tmp_ctxt = heaan.Ciphertext(context)
        enc.encrypt(one_msg,keypack,tmp_ctxt)
        mask_ = [0]*num_slot
        mask_[i*25]=1
        mask_msg = heaan.Message(log_num_slot)
        for k in range(0,num_slot):
            mask_msg[k] = mask_[k]
        # mask_msg.set_data(mask_)
        # mask_msg.to_device()
        if i ==0:
            eval.mult(input_ctxt,mask_msg, tmp_ctxt)
            check_boot(tmp_ctxt,eval)
            eval.add(return_ctxt, tmp_ctxt,return_ctxt)
        else:
            eval.right_rotate(duplicate_ctxt,24,duplicate_ctxt)
            check_boot(duplicate_ctxt,eval)
            eval.mult(duplicate_ctxt,mask_msg, tmp_ctxt)
            check_boot(tmp_ctxt,eval)
            check_boot(duplicate_ctxt,eval)
            eval.add(return_ctxt, tmp_ctxt,return_ctxt)

    return return_ctxt

def make_25_ctxt(ctxt,eval):
    origin = heaan.Ciphertext(ctxt)
    tmp_ = heaan.Ciphertext(ctxt)
    eval.right_rotate(ctxt,1,tmp_)
    check_boot(ctxt,eval)
    eval.add(ctxt, tmp_,ctxt)

    eval.right_rotate(ctxt,2,tmp_)
    check_boot(ctxt,eval)
    eval.add(ctxt, tmp_,ctxt)

    eval.right_rotate(ctxt,4,tmp_)
    check_boot(ctxt,eval)
    eval.add(ctxt, tmp_,ctxt)

    ctxt_8_ = heaan.Ciphertext(ctxt)
    eval.right_rotate(ctxt_8_,16,ctxt_8_)
    check_boot(ctxt_8_,eval)

    eval.right_rotate(ctxt,8,tmp_)
    check_boot(ctxt,eval)
    eval.add(ctxt, tmp_,ctxt)
    eval.add(ctxt_8_,ctxt,ctxt)

    eval.right_rotate(origin,24,origin)
    check_boot(origin,eval)

    eval.add(ctxt,origin,ctxt)
    check_boot(ctxt,eval)

    return ctxt

def make_inverse_ctxt(model_ctxt_path, eval, context,keypack,alpha, col_max_list):
    enc = heaan.Encryptor(context)

    f_list = os.listdir(model_ctxt_path)
    file_list = []
    for i in f_list:
        if 'total' not in i:
            file_list.append(re.sub('.ctxt','',i))
    file_list = natsort.natsorted(file_list)

    model_cdict = load_ctxt(file_list,model_ctxt_path,context)

    one_ = [0]*num_slot
    one_msg = heaan.Message(log_num_slot)
    for i in range(0,num_slot):
        one_msg[i] = one_[i]
    # one_msg.set_data(one_)

    inverse_index = {}

    inverse_ctxt = heaan.Ciphertext(context)
    enc.encrypt(one_msg, keypack, inverse_ctxt)
    # inverse_ctxt.to_device()

    count_ctxt = heaan.Ciphertext(context)
    enc.encrypt(one_msg, keypack, count_ctxt)
    # count_ctxt.to_device()

    for i,n in enumerate(file_list):
        if 'log' not in n :
            inverse_index[i] = n

    total_num_ctxt = heaan.Ciphertext(context)
    total_num_ctxt.load(model_ctxt_path+'total_num.ctxt')
    # total_num_ctxt.to_device()

    for i,n in enumerate(inverse_index):
        tmp = [0]*num_slot
        tmp[i]=1
        tmp_msg = heaan.Message(log_num_slot)
        for k in range(0,num_slot):
            tmp_msg[k] = tmp[k]
        # tmp_msg.set_data(data = tmp)
        # tmp_msg.to_device()
        # model_cdict[inverse_index[n]].to_device()

        if 'X' in inverse_index[n]:

            eval.mult(model_cdict[inverse_index[n]],tmp_msg,model_cdict[inverse_index[n]])
            check_boot(model_cdict[inverse_index[n]],eval)

            eval.add(model_cdict[inverse_index[n]],count_ctxt,count_ctxt)

        else:

            tmp_ctxt1 = heaan.Ciphertext(context)
            enc.encrypt(one_msg, keypack, tmp_ctxt1)
            # tmp_ctxt1.to_device()
            eval.mult(model_cdict[inverse_index[n]],tmp_msg,tmp_ctxt1)
            check_boot(tmp_ctxt1,eval)

            eval.add(tmp_ctxt1,count_ctxt,count_ctxt)

    tmp_ctxt = heaan.Ciphertext(context)
    enc.encrypt(one_msg, keypack, tmp_ctxt)
    # tmp_ctxt.to_device()

    tc = [0]*num_slot

    unit_size = 0
    for i in range(len(col_max_list)-1):
        unit_size+=col_max_list[i]
    unit_size+=1

    y_loca = 0
    for _ in range(col_max_list[-1]):
        tc[y_loca]=1
        y_loca+=unit_size

    y_loc_msg = heaan.Message(log_num_slot)
    for k in range(0,num_slot):
        y_loc_msg[k] = tc[k]
    # y_loc_msg.set_data(tc)
    # y_loc_msg.to_device()
    eval.mult(total_num_ctxt,y_loc_msg,total_num_ctxt)
    eval.add(total_num_ctxt,inverse_ctxt,inverse_ctxt)

    for i in range(1,col_max_list[-1]+1):
        tc = [0]*num_slot
        for j in range(unit_size*(i-1),unit_size*i):
            if j ==unit_size*(i-1):
                pass
            else :
                tc[j]=1
        y_tmp_msg = heaan.Message(log_num_slot)
        for k in range(0,num_slot):
            y_tmp_msg[k] = tc[k]
        # y_tmp_msg.set_data(tc)
        # y_tmp_msg.to_device()
        eval.mult(model_cdict[str(i)+'acountY_'], y_tmp_msg,model_cdict[str(i)+'acountY_'])
        eval.add(model_cdict[str(i)+'acountY_'],inverse_ctxt,inverse_ctxt)

    nc = [0]*num_slot
    unit_ = [0]*unit_size

    cur=1
    for j in range(len(col_max_list[:-1])):
        ni = col_max_list[j]
        for i in range(cur,cur+ni):
            unit_[i]=alpha*ni
        cur+=ni

    unit_msg = unit_*col_max_list[-1]
    for i,ui in enumerate(unit_msg):
        nc[i]=ui

    nc_msg = heaan.Message(log_num_slot)
    for k in range(0,num_slot):
        nc_msg[k] = nc[k]
    # nc_msg.set_data(nc)
    nc_ctxt = heaan.Ciphertext(context)
    enc.encrypt(nc_msg,keypack,nc_ctxt)
    # nc_ctxt.to_device()

    eval.add(nc_ctxt,inverse_ctxt,inverse_ctxt)

    eval.mult(inverse_ctxt, 0.0001,inverse_ctxt)
    eval.mult(count_ctxt,0.0001,count_ctxt)
    check_boot(inverse_ctxt,eval)
    check_boot(count_ctxt,eval)

    heaan.math.approx.inverse(eval, inverse_ctxt, inverse_ctxt,greater_than_one = False)
    check_boot(inverse_ctxt,eval)

    eval.mult(inverse_ctxt, count_ctxt, inverse_ctxt)

    return inverse_ctxt, inverse_index

def make_log_ctxt(m_25_ctxt, eval, context,keypack):
    key_file_path = "./key"
    sk = heaan.SecretKey(context,key_file_path+"/secretkey.bin")
    dec = heaan.Decryptor(context)

    check_boot(m_25_ctxt,eval)
    log_ctxt = NB_log.find_log(m_25_ctxt,eval,keypack,log_num_slot,context,dec,sk)

    return log_ctxt

def findMax4(c, context, keypack, logN, ndata,eval):
    enc = heaan.Encryptor(context)
    if (ndata==1):
        return c
    check_boot(c,eval)
    if (ndata % 4 !=0):
        i=ndata
        msg = heaan.Message(logN-1,0)
        while (i % 4 !=0):
            msg[i]=0.00000
            i+=1
        ndata=i
        eval.add(c,msg,c)

    ms1=heaan.Message(log_num_slot)
    for i in range(num_slot):
        ms1[i]=0
    for i in range(ndata//4):
        ms1[i]=1

    msg1 = heaan.Ciphertext(context)
    enc.encrypt(ms1,keypack,msg1)
    # msg1.to_device()

    ca = heaan.Ciphertext(context)
    cb = heaan.Ciphertext(context)
    cc = heaan.Ciphertext(context)
    cd = heaan.Ciphertext(context)
    c1 = heaan.Ciphertext(context)
    c2 = heaan.Ciphertext(context)
    c3 = heaan.Ciphertext(context)
    c4 = heaan.Ciphertext(context)
    c5 = heaan.Ciphertext(context)
    c6 = heaan.Ciphertext(context)
    ctmp1 = heaan.Ciphertext(context)
    ctmp2 = heaan.Ciphertext(context)
    # ca.to_device()
    # cb.to_device()
    # cc.to_device()
    # cd.to_device()
    # c1.to_device()
    # c2.to_device()
    # c3.to_device()
    # c4.to_device()
    # c5.to_device()
    # c6.to_device()
    # ctmp1.to_device()
    # ctmp2.to_device()

    eval.mult(c,msg1,ca)
    eval.left_rotate(c,ndata//4,ctmp1)
    eval.mult(ctmp1,msg1,cb)
    eval.left_rotate(c,ndata//2,ctmp1)
    eval.mult(ctmp1,msg1,cc)
    eval.left_rotate(c,ndata*3//4,ctmp1)
    eval.mult(ctmp1,msg1,cd)

    check_boot(ca,eval)
    check_boot(cb,eval)
    check_boot(cc,eval)
    check_boot(cd,eval)

    eval.sub(ca,cb,c1)
    eval.sub(cb,cc,c2)
    eval.sub(cc,cd,c3)
    eval.sub(cd,ca,c4)
    eval.sub(ca,cc,c5)
    eval.sub(cb,cd,c6)

    eval.right_rotate(c2,ndata//4,ctmp1)
    eval.add(ctmp1,c1,ctmp1)

    eval.right_rotate(c3,ndata//2,ctmp2)
    eval.add(ctmp1,ctmp2,ctmp1)

    eval.right_rotate(c4,ndata*3//4,ctmp2)
    eval.add(ctmp1,ctmp2,ctmp1)

    eval.right_rotate(c5,ndata,ctmp2)
    eval.add(ctmp1,ctmp2,ctmp1)

    eval.right_rotate(c6,5*ndata//4,ctmp2)
    eval.add(ctmp1,ctmp2,ctmp1)

    c0 = heaan.Ciphertext(context)
    heaan.math.approx.sign(eval,ctmp1,c0)
    check_boot(c0,eval)

    c0_c = heaan.Ciphertext(c0)

    mkmsg = [1.0]*num_slot
    mkall = heaan.Message(log_num_slot)
    for k in range(0,num_slot):
        mkall[k] = mkmsg[k]
    # mkall.set_data(mkmsg)
    # mkall.to_device()
    eval.add(c0,mkall,c0)
    eval.mult(c0,0.5,c0)
    check_boot(c0,eval)

    ceq = heaan.Ciphertext(context)
    # ceq.to_device()
    eval.square(c0_c,ceq)
    check_boot(ceq,eval)
    eval.negate(ceq,ceq)
    eval.add(ceq,mkall,ceq)

    mk1 = heaan.Ciphertext(msg1)
    # mk1.to_device()
    mk2 = heaan.Ciphertext(context)
    mk3 = heaan.Ciphertext(context)
    mk4 = heaan.Ciphertext(context)
    mk5 = heaan.Ciphertext(context)
    mk6 = heaan.Ciphertext(context)
    # mk2.to_device()
    # mk3.to_device()
    # mk4.to_device()
    # mk5.to_device()
    # mk6.to_device()

    eval.right_rotate(mk1,ndata//4,mk2)
    eval.right_rotate(mk2,ndata//4,mk3)
    eval.right_rotate(mk3,ndata//4,mk4)
    eval.right_rotate(mk4,ndata//4,mk5)
    eval.right_rotate(mk5,ndata//4,mk6)

    c_neg = heaan.Ciphertext(c0)
    # c_neg.to_device()
    eval.negate(c0,c_neg)

    eval.add(c_neg,mkall,c_neg)

    c0n = heaan.Ciphertext(c0)
    # c0n.to_device()
    eval.mult(c0n,mk1,ctmp1)
    ctxt=c0n
    c_ab = heaan.Ciphertext(ctmp1)

    c0=heaan.Ciphertext(ctxt)
    eval.mult(c_neg,mk4,ctmp2)
    eval.left_rotate(ctmp2,(3*ndata)//4,ctmp2)
    eval.mult(ctmp1,ctmp2,ctmp1)

    eval.mult(c0,mk5,ctmp2)
    eval.left_rotate(ctmp2,ndata,ctmp2)

    cca = heaan.Ciphertext(context)
    eval.mult(ctmp1,ctmp2,cca)

    eval.mult(c_neg,mk1,ctmp1)
    eval.mult(c0,mk2,ctmp2)
    eval.left_rotate(ctmp2,ndata//4,ctmp2)
    c_bc = heaan.Ciphertext(ctmp2)
    eval.mult(ctmp1,ctmp2,ctmp1)

    eval.mult(c0,mk6,ctmp2)
    eval.left_rotate(ctmp2,ndata*5//4,ctmp2)
    ccb = heaan.Ciphertext(context)
    eval.mult(ctmp1,ctmp2,ccb)

    eval.mult(c_neg,mk2,ctmp1)
    eval.left_rotate(ctmp1,ndata//4,ctmp1)
    eval.mult(c0,mk3,ctmp2)
    eval.left_rotate(ctmp2,ndata//2,ctmp2)
    c_cd = heaan.Ciphertext(ctmp2)
    # c_cd.to_device()
    eval.mult(ctmp1,ctmp2,ctmp1)
    eval.mult(c_neg,mk5,ctmp2)
    eval.left_rotate(ctmp2,ndata,ctmp2)
    ccc = heaan.Ciphertext(context)
    # ccc.to_device()
    eval.mult(ctmp1,ctmp2,ccc)

    eval.mult(c_neg,mk3,ctmp1)
    eval.left_rotate(ctmp1,ndata//2,ctmp1)
    eval.mult(c0,mk4,ctmp2)
    eval.left_rotate(ctmp2,3*ndata//4,ctmp2)
    cda = heaan.Ciphertext(ctmp2)
    eval.mult(ctmp1,ctmp2,ctmp1)

    eval.mult(c_neg,mk6,ctmp2)
    eval.left_rotate(ctmp2,5*ndata//4,ctmp2)

    ccd = heaan.Ciphertext(context)
    # ccd.to_device()
    eval.mult(ctmp1,ctmp2,ccd)

    check_boot(cca,eval)
    check_boot(ccb,eval)
    check_boot(ccc,eval)
    check_boot(ccd,eval)

    eval.mult(cca,ca,cca)
    eval.mult(ccb,cb,ccb)
    eval.mult(ccc,cc,ccc)
    eval.mult(ccd,cd,ccd)

    cout = heaan.Ciphertext(cca)
    eval.add(cout,ccb,cout)
    eval.add(cout,ccc,cout)
    eval.add(cout,ccd,cout)

    check_boot(cout,eval)

    cneq = heaan.Ciphertext(context)
    # cneq.to_device()
    eval.negate(ceq,cneq)
    eval.add(cneq,mkall,cneq)
    cneq_da = heaan.Ciphertext(context)
    # cneq_da.to_device()
    eval.left_rotate(cneq,(3*ndata)//4,cneq_da)
    eval.mult(cneq_da,mk1,cneq_da)

    cneq_bc = heaan.Ciphertext(context)
    # cneq_bc.to_device()
    eval.left_rotate(cneq,(ndata)//4,cneq_bc)
    eval.mult(cneq_bc,mk1,cneq_bc)

    ceq_ab = heaan.Ciphertext(context)
    # ceq_ab.to_device()
    eval.mult(ceq,mk1,ceq_ab)

    ceq_bc = heaan.Ciphertext(context)
    # ceq_bc.to_device()
    eval.left_rotate(ceq,(ndata)//4,ceq_bc)
    eval.mult(ceq_bc,mk1,ceq_bc)

    ceq_cd = heaan.Ciphertext(context)
    # ceq_cd.to_device()
    eval.left_rotate(ceq,(ndata)//2,ceq_cd)
    eval.mult(ceq_cd,mk1,ceq_cd)

    ceq_da = heaan.Ciphertext(context)
    # ceq_da.to_device()
    eval.negate(cneq_da,ceq_da)
    eval.add(ceq_da,mk1,ceq_da)
    check_boot(ceq,eval)
    check_boot(ceq_ab,eval)
    check_boot(ceq_bc,eval)
    check_boot(ceq_cd,eval)
    check_boot(ceq_da,eval)

    eval.mult(ceq_ab,ceq_bc,ctmp2)
    eval.mult(ctmp2,c_cd,ctmp1)
    eval.bootstrap(ctmp1, ctmp1)
    c_cond3 = heaan.Ciphertext(ctmp1)

    eval.mult(ceq_bc,ceq_cd,ctmp1)
    eval.mult(ctmp1,cda,ctmp1)
    eval.add(c_cond3,ctmp1,c_cond3)

    eval.mult(ceq_cd,ceq_da,ctmp1)
    eval.mult(ctmp1,c_ab,ctmp1)
    eval.add(c_cond3,ctmp1,c_cond3)

    eval.mult(ceq_ab,ceq_da,ctmp1)
    eval.mult(ctmp1,c_bc,ctmp1)
    eval.add(c_cond3,ctmp1,c_cond3)

    c_cond4 = heaan.Ciphertext(context)
    eval.mult(ctmp2,ceq_cd,c_cond4)

    eval.bootstrap(c_cond3, c_cond3)
    eval.bootstrap(c_cond4, c_cond4)

    c_tba = heaan.Ciphertext(context)
    eval.mult(c_cond3,0.333333333,c_tba)
    eval.bootstrap(c_tba, c_tba)
    eval.add(c_tba,mkall,c_tba)
    eval.bootstrap(c_cond4, c_cond4)
    eval.add(c_cond4,mkall,ctmp1)
    eval.mult(c_tba,ctmp1,c_tba)
    eval.mult(cout,c_tba,cout)
    eval.bootstrap(cout, cout)

    return findMax4(cout, context, keypack, logN, ndata//4,eval)

def findMaxPos(c,context,kpack,logN,ndata,eval):
    cmax = findMax4(c,context,kpack,logN,ndata,eval)
    ctmp = heaan.Ciphertext(context)
    for i in range(logN-1):
        eval.right_rotate(cmax,pow(2,i),ctmp)
        eval.add(cmax,ctmp,cmax)
    eval.sub(c,cmax,c)
    c_red = heaan.Ciphertext(context)
    eval.add(c,0.000001,c)
    # heaan.math.approx.greater_than_zero(eval,c,c_red)
    greater_than_zero_(eval,c,c_red)

    c_out=selectRandomOnePos(c_red,context,kpack,logN,ndata,eval)
    return c_out

def greater_than_zero_(eval,ctxt,result_ctxt):
    tmp = heaan.Ciphertext(context)
    tmp2 = heaan.Ciphertext(context)

    heaan.math.approx.sign(eval,ctxt,tmp)
    check_boot(tmp,eval)

    eval.add(tmp, 1, tmp2)

    eval.mult(tmp,tmp2,tmp)
    check_boot(tmp,eval)

    eval.mult(tmp, 0.5, result_ctxt)
    check_boot(result_ctxt,eval)

def selectRandomOnePos(c_red,context,kpack,logN,ndata,eval):
    enc = heaan.Encryptor(context)
    m0 = heaan.Message(logN,0.0)
    c_sel = heaan.Ciphertext(context)
    enc.encrypt(m0,kpack,c_sel)
    # c_sel.to_device()
    rando = np.random.permutation(ndata)
    ctmp1 = heaan.Ciphertext(c_red)
    # ctmp1.to_device()

    if (ctmp1.level-4< eval.min_level_for_bootstrap):
         eval.bootstrap(ctmp1,ctmp1)
    ctmp2 = heaan.Ciphertext(context)
    # ctmp2.to_device()

    m0[0]=1.0
    # m0.to_device()
    for l in rando:
        if (l>0):

            if (ctmp1.level-4< eval.min_level_for_bootstrap):
                eval.bootstrap(ctmp1,ctmp1)

            if (c_sel.level-4< eval.min_level_for_bootstrap):
                eval.bootstrap(c_sel,c_sel)

            eval.left_rotate(ctmp1,l,ctmp1)
            eval.mult(c_sel,ctmp1,ctmp2)
            eval.sub(ctmp1,ctmp2,ctmp1)
            eval.mult(ctmp1,m0,ctmp2)
            eval.right_rotate(ctmp1,l,ctmp1)
            eval.add(c_sel,ctmp2,c_sel)
        else:

            if (ctmp1.level - 4< eval.min_level_for_bootstrap):
                eval.bootstrap(ctmp1,ctmp1)

            if (c_sel.level-4< eval.min_level_for_bootstrap):
                eval.bootstrap(c_sel,c_sel)
            eval.mult(c_sel,ctmp1,ctmp2)
            eval.sub(ctmp1,ctmp2,ctmp1)
            eval.mult(ctmp1,m0,ctmp2)
            eval.add(c_sel,ctmp2,c_sel)

    if (ctmp1.level - 4 < eval.min_level_for_bootstrap):
        eval.bootstrap(ctmp1,ctmp1)

    return ctmp1

def _add_one_zero_column(tmp, column_name,n):
    result = [0]*len(tmp)
    for i,cc in enumerate(tmp[column_name]):
        if cc == n:
            result[i] = 1
        if "feature" in column_name :
            tmp["X_"+column_name[-1]+"_"+str(n)]=result
        else :
            tmp[str(n)+"Y_"] = result

def load_ctxt(fn_list,ctxt_path,context):
    out_cdict={}
    for cname in fn_list:
        ctxt = heaan.Ciphertext(context)
        ctxt.load(ctxt_path+cname+".ctxt")
        out_cdict[cname]=ctxt
    return out_cdict

def rotate_sum(input_ctxt,eval):
    tmp_ctxt = heaan.Ciphertext(context)
    for i in range(int(np.log2(num_slot))):
        eval.left_rotate(input_ctxt, 2**i, tmp_ctxt)
        check_boot(tmp_ctxt,eval)
        eval.add(input_ctxt, tmp_ctxt, input_ctxt)
    return input_ctxt

def check_boot(x,eval):
    if x.level==3:
        eval.bootstrap(x, x)
    elif x.level<3:
        exit(0)
    return x

def print_ctxt(c,dec,sk,logN,size):
    # c.to_host()
    m=heaan.Message(logN)
    dec.decrypt(c,sk,m)
    for i in range(size):
        print(i,m[i])
        if (math.isnan(m[i].real)):
            print ("nan detected..stop")
            exit(0)
    # c.to_device()


def virus(arr):
    dx = [1,-1,0,0]
    dy = [0,0,1,-1]
    s = []
    for i in range(N):
        for j in range(M):
            if arr[i][j]==2:
                s.append((i,j))
                while len(s)!=0:
                    x,y = s.pop()
                    for k in range(4):
                        nx = x + dx[k]
                        ny = y + dy[k]
                        if 0<=nx<N and 0<=ny<M:
                            if arr[nx][ny]==0:
                                arr[nx][ny]=4
                                s.append((nx,ny))

N, M = map(int,input().split())

base = [list(map(int,input().split()))for _ in range(N)]

p = []

# 벽 세울 수 있는 가능성 찾기
for x1 in range(N):
    for y1 in range(M):
        if base[x1][y1]==0:
            for x2 in range(N):
                for y2 in range(M):
                    if (x1,y1)!=(x2,y2):
                        if base[x2][y2]==0:
                            for x3 in range(N):
                                for y3 in range(M):
                                    if (x1,y1)!=(x3,y3) and (x2,y2)!=(x3,y3):
                                        if base[x3][y3]==0:
                                            p.append((x1,y1,x2,y2,x3,y3))
# print(len(p))
max=0
while len(p)!=0:
    x1,y1,x2,y2,x3,y3 = p.pop()
    base[x1][y1], base[x2][y2], base[x3][y3] = 3, 3, 3
    virus(base)
    # for row in base:
    #     print(row)
    cnt=0
    for i in range(N):
        for j in range(M):
            if base[i][j]==0:
                cnt +=1
            if base[i][j]==3 or base[i][j]==4:
                base[i][j]=0
    if max<cnt:
        max = cnt
    # print(cnt)
    # print()

print(max)


from discord.ext import commands
from discord import activity

from secrets import token
from util.cogUtil import load_all_cogs, reload_all_cogs
from util.util import (quick_response, error_response)

from util.checks import is_owner

bot = commands.Bot('.')

@bot.event
async def on_ready():
    """On ready event to setup the bot"""
    await bot.change_presence(activity=activity.Game(name="Help: .help"))

    print('Online!')

@bot.command()
@commands.check(is_owner)
async def load(ctx: discord.ext.context, extension: str):
    """Load command for cogs"""
    bot.load_extension(f'cogs.{extension}')
    try:
        await quick_response(ctx.channel, f'{extension.title()} loaded.')
    except commands.ExtensionNotLoaded or commands.ExtensionNotFound:
        await error_response(ctx, 'Failed to load!')
        return

@bot.command()
@commands.check(is_owner)
async def unload(ctx, extension: str):
    """Unload command for cogs"""
    bot.unload_extension(f'cogs.{extension}')
    try:
        await quick_response(ctx.channel, f'{extension.title()} unloaded.')
    except commands.ExtensionNotLoaded or commands.ExtensionNotFound:
        await error_response(ctx, 'Failed to unload!')
        return

@bot.command()
@commands.check(is_owner)
async def reload(ctx, extension=None):
    """Reload command for cogs"""
    extensions_loaded = []
    if extension == "all" or extension is None:
        extensions_loaded = reload_all_cogs(bot)
    else:
        try:
            bot.reload_extension(f'cogs.{extension}')
            extensions_loaded.append(extension)
        except commands.ExtensionNotLoaded or commands.ExtensionNotFound:
            await error_response(ctx, 'Failed to reload!')
            return
    await quick_response(ctx.channel, f'{str.join(", ", extensions_loaded)} loaded!')

# load the cogs when the bot starts
load_all_cogs(bot)
# run the bot
bot.run(token)