import numpy as np
import pandas as pd
import random
import math
from datetime import date
from scipy.stats import binom
from sklearn.model_selection import StratifiedKFold
from pyod.models.knn import KNN
from pyod.models.iforest import IForest
from pyod.models.ocsvm import OCSVM
from sklearn.isotonic import IsotonicRegression
from sklearn.linear_model import LogisticRegression
from betacal import BetaCalibration
from beta_calibration import*

def compute_confidence_error(model, Dtrain, y, splits = 5, iterations = 1000, saveresults = True):

    """
    Evaluate the example-wise confidence of different methods, included the model ExCeeD provided in the paper.
    First, we split the data set in training and test set using a k fold crossvalidation. Second, we estimate the
    example-wise confidence for ExCeeD, ExCeed_sp (with second prior), ExCeeD with outlier probability computed
    through the linear, squashing and unify methods, and calibrated probabilities through Logistic (logcal),
    Isotonic (isocal) and Beta (betacal) Calibrations. Third, we empirically estimate frequencies of class prediction
    for each example. Finally, we evaluate the different methods by taking the mean L2 error per class.

    Parameters
    ----------
    model      : string, claiming the model to use for evaluating the confidence. It can be one of: KNN, IForest, OCSVM.
    Dtrain     : list of shape (n_samples, n_features) containing the dataset with only features.
    y          : list of shape (n_samples,) assuming 1 if the example is an anomaly, 0 if it is normal.
    splits     : int regarding the number of splits to make during the stratified crossvalidation phase.
    iterations : int representing the number of iterations to make when empirically assessing the class frequencies.

    Returns
    ----------
    l2_error   : dictionary with values [a,b], where a stand for the mean L2 error for normal examples, b for anomalies.

    """
    np.random.seed(331)

    contamination = sum(y)/len(y) #the real contamination factor. We assume it is known.

    if contamination == 0:
        print('Error, contamination factor cannot be equal to 0')
        return;

    skf = StratifiedKFold(n_splits=splits, shuffle=True)

    l2_error = {'ExCeeD': np.zeros(2, np.float), 'ExCeeD_sp': np.zeros(2, np.float), 'Squash': np.zeros(2, np.float),
                'Linear': np.zeros(2, np.float), 'Unify': np.zeros(2, np.float), 'LogCal': np.zeros(2, np.float),
                'IsoCal': np.zeros(2, np.float), 'BetaCal': np.zeros(2, np.float), 'Baseline': np.zeros(2, np.float)}

    idx_crossval = 0
    for train_index, test_index in skf.split(Dtrain, y):

        idx_crossval += 1

        X_train, X_test = Dtrain[train_index], Dtrain[test_index]
        y_train, y_test = y[train_index], y[test_index]

        exceed_conf, exceed_conf_otherprior, squash_conf, linear_conf, unify_conf, logcal_conf, isocal_conf, betacal_conf,\
        prediction = confidence_estimation(X_train, y_train, X_test, y_test, contamination, model)
        frequence = np.asarray(empirical_frequencies(iterations, X_train, X_test, contamination, model))
        anomalies = np.where(prediction == 1)[0] #indexes of normals
        normals = np.where(prediction == 0)[0]   #indexes of anomalies

        if saveresults:
            savedf_results(exceed_conf, exceed_conf_otherprior, squash_conf, linear_conf, unify_conf, logcal_conf, isocal_conf,
                        betacal_conf, frequence, prediction, y_test, idx_crossval)

        l2_error['ExCeeD'] += [l2_distance(exceed_conf[normals], frequence[normals])/splits,
                              l2_distance(exceed_conf[anomalies], frequence[anomalies])/splits]

        l2_error['ExCeeD_sp'] += [l2_distance(exceed_conf_otherprior[normals],frequence[normals])/splits,
                            l2_distance(exceed_conf_otherprior[anomalies], frequence[anomalies])/splits]

        l2_error['Squash'] += [l2_distance(squash_conf[normals], frequence[normals])/splits,
                          l2_distance(squash_conf[anomalies], frequence[anomalies])/splits]

        l2_error['Linear'] += [l2_distance(linear_conf[normals], frequence[normals])/splits,
                          l2_distance(linear_conf[anomalies], frequence[anomalies])/splits]

        l2_error['Unify'] += [l2_distance(unify_conf[normals], frequence[normals])/splits,
                          l2_distance(unify_conf[anomalies], frequence[anomalies])/splits]

        l2_error['LogCal'] += [l2_distance(logcal_conf[normals], frequence[normals])/splits,
                          l2_distance(logcal_conf[anomalies], frequence[anomalies])/splits]

        l2_error['IsoCal'] += [l2_distance(isocal_conf[normals], frequence[normals])/splits,
                          l2_distance(isocal_conf[anomalies], frequence[anomalies])/splits]

        l2_error['BetaCal'] += [l2_distance(betacal_conf[normals], frequence[normals])/splits,
                          l2_distance(betacal_conf[anomalies], frequence[anomalies])/splits]

        l2_error['Baseline'] += [l2_distance(np.ones(len(normals)), frequence[normals])/splits,
                          l2_distance(np.ones(len(anomalies)), frequence[anomalies])/splits]

    for key in l2_error.keys():
        l2_error[key] = [round(sum(l2_error[key])/2,6)]

    L2_error = pd.DataFrame.from_dict(l2_error)

    return L2_error

def confidence_estimation(X_train, y_train, X_test, y_test, contamination, model):

    """
    Estimate the example-wise confidence of different methods, included the model ExCeeD provided in the paper.
    First, we compute the outlier probabilities for all the methods but Calibrations. Then, we estimate the
    example-wise confidence for ExCeeD, ExCeed_sp (with second prior), ExCeeD with outlier probability computed
    through the linear, squashing and unify methods, and calibrated probabilities through Logistic (logcal),
    Isotonic (isocal) and Beta (betacal) Calibrations.

    Parameters
    ----------
    X_train       : list of shape (n_train, n_features) containing the training set with only features.
    y_train       : list of shape (n_train,) containing the actual labels for the training set. It is needed for Calibration.
    X_test        : list of shape (n_test, n_features) containing the test set with only features.
    y_test        : list of shape (n_test,) containing the actual labels for the test set. It is needed for Calibration.
    contamination : float representing the expected proportion of anomalies in the training set.
    model         : string, claiming the model to use for evaluating the confidence. It can be one of: KNN, IForest, OCSVM.

    Returns
    ----------
    exceed_conf    : example-wise confidence using ExCeeD (outlier probability computed by Bayesian Learning with uniform prior)
    exceed_conf_sp : example-wise confidence using ExCeeD (outlier probability computed by Bayesian Learning with other prior)
    squash_conf    : example-wise confidence using ExCeeD (outlier probability computed by squashing function)
    linear_conf    : example-wise confidence using ExCeeD (outlier probability computed by linear function)
    unify_conf     : example-wise confidence using ExCeeD (outlier probability computed by unify method)
    logcal_conf    : example-wise calibrated probability using Logistic Calibration
    isocal_conf    : example-wise calibrated probability using Isotonic Calibration
    betacal_conf   : example-wise calibrated probability using Beta Calibration
    prediction     : list of class predictions with shape (n_test,)

    """
    np.random.seed(331)
    n = np.shape(X_train)[0]
    clf = train_model(X_train, contamination, model)
    col = clf.decision_function(X_train)
    prediction = clf.predict(X_test)
    test_scores = clf.decision_function(X_test)
    train_scores = clf.decision_function(X_train)

    n_anom = np.int(n*contamination)
    m = 10/contamination

    count_instances = np.vectorize(lambda x: np.count_nonzero(train_scores <= x))
    n_instances = count_instances(test_scores)

    prob_func = np.vectorize(lambda x: (1+x)/(2+n))
    exceed_posterior = prob_func(n_instances)

    adj_prob_func = np.vectorize(lambda x: (10+x)/(m+n))
    exceed_posterior_sp = adj_prob_func(n_instances)

    unify_proba_anom = [x[1] for x in clf.predict_proba(X_test, method='unify')]

    linear_proba_anom = [x[1] for x in clf.predict_proba(X_test, method='linear')]

    tmp_score = sorted(col, reverse = True)
    gamma = tmp_score[min(np.int(n*contamination)-1,0)]
    squashing_proba_anom = [1-squash_proba(x, gamma) for x in clf.decision_function(X_test)]

    mapinto01_train = [1-squash_proba(x, gamma) for x in clf.decision_function(X_train)]
    mapinto01_test = [1-squash_proba(x, gamma) for x in clf.decision_function(X_test)]

    lr = LogisticRegression(C=99999999999)
    lr.fit(np.asarray(mapinto01_train).reshape(-1, 1), y_train)
    logistic_calibration = lr.predict_proba(np.asarray(mapinto01_test).reshape(-1, 1))[:,1]

    iso = IsotonicRegression()
    iso.fit(mapinto01_train, y_train)
    isotonic_calibration = np.nan_to_num(iso.predict(mapinto01_test), nan = 1.0)

    bc = BetaCalibration(parameters="abm")
    bc.fit(np.asarray(mapinto01_train).reshape(-1, 1), y_train)
    beta_calibration = bc.predict(np.asarray(mapinto01_test).reshape(-1, 1))

    conf_func = np.vectorize(lambda p: 1 - binom.cdf(n - n_anom, n, p))

    exceed_conf = conf_func(exceed_posterior)
    np.place(exceed_conf, prediction == 0, 1 - exceed_conf[prediction == 0])

    exceed_conf_sp = conf_func(exceed_posterior_sp)
    np.place(exceed_conf_sp, prediction == 0, 1 - exceed_conf_sp[prediction == 0])

    squash_conf = conf_func(squashing_proba_anom)
    np.place(squash_conf, prediction == 0, 1 - squash_conf[prediction == 0])

    linear_conf = conf_func(linear_proba_anom)
    np.place(linear_conf, prediction == 0, 1 - linear_conf[prediction == 0])

    unify_conf = conf_func(unify_proba_anom)
    np.place(unify_conf, prediction == 0, 1 - unify_conf[prediction == 0])

    logcal_conf = np.asarray([round(x,4) if prediction[i] == 1 else round(1-x,4) for i,x in enumerate(logistic_calibration)])
    isocal_conf = np.asarray([round(x,4) if prediction[i] == 1 else round(1-x,4) for i,x in enumerate(isotonic_calibration)])
    betacal_conf = np.asarray([round(x,4) if prediction[i] == 1 else round(1-x,4) for i,x in enumerate(beta_calibration)])

    return exceed_conf, exceed_conf_sp, squash_conf, linear_conf, unify_conf, logcal_conf, isocal_conf, betacal_conf, prediction

def empirical_frequencies(iterations, X_train, X_test, contamination, model):

    """
    Empirically estimate frequencies of class prediction for each example in the test set. The method does n_iter = iterations.

    Parameters
    ----------
    iterations    : int representing the number of iterations to make when empirically assessing the class frequencies.
    X_train       : list of shape (n_train, n_features) containing the training set with only features.
    X_test        : list of shape (n_test, n_features) containing the test set with only features.
    contamination : float representing the expected proportion of anomalies in the training set.
    model         : string, claiming the model to use for evaluating the confidence. It can be one of: KNN, IForest, OCSVM.

    Returns
    ----------
    frequence     : list of shape (n_test,) containing the empirical frequencies for each example in the test set.

    """
    np.random.seed(331)
    n = np.shape(X_train)[0]
    empirical_freq = np.zeros(len(X_test), np.double)
    clf = train_model(X_train, contamination, model)
    pred = clf.predict(X_test)
    for iteration in range(iterations):
        sizetset = random.sample(range(np.int(0.2*n), n), 1)
        indexes_tset = random.sample(range(n), sizetset[0])
        subX_train = X_train[indexes_tset]
        clf2 = train_model(subX_train, contamination, model)
        prediction = clf2.predict(X_test)
        empirical_freq += prediction
    empirical_freq = [empirical_freq[i]/iterations if pred[i] == 1 else 1-empirical_freq[i]/iterations\
                      for i in range(len(X_test))]
    frequence = [round(min(1,empirical_freq[i]),4) for i in range(len(X_test))]

    return frequence

def train_model(X_train, contamination, model):

    """
    Train the model based on the user's choice (KNN, IForest, OCSVM).

    Parameters
    ----------
    X_train       : list of shape (n_train, n_features) containing the training set with only features.
    contamination : float representing the expected proportion of anomalies in the training set.
    model         : string, claiming the model to use for evaluating the confidence. It can be one of: KNN, IForest, OCSVM.

    Returns
    ----------
    clf           : obj with the model trained on the training set.

    """
    np.random.seed(331)
    n = np.shape(X_train)[0]
    if model == 'KNN':
        clf = KNN(n_neighbors=max(np.int(n*contamination),1), contamination = contamination).fit(X_train)
    elif model == 'IForest':
        clf = IForest(contamination = contamination, random_state = 331).fit(X_train)
    elif model == 'OCSVM':
        clf = OCSVM(contamination = contamination).fit(X_train)

    return clf

def squash_proba(x, gamma):
    gamma = max(0.0001, gamma)
    return 2**(-(x/gamma)**2)

def l2_distance(confidence, frequence):
    if len(confidence) == 0:
        return 0;
    else:
        return sum((confidence - frequence)**2)/len(confidence)

def savedf_results(exceed_conf, exceed_conf_otherprior, squash_conf, linear_conf, unify_conf, logcal_conf, isocal_conf,
                        betacal_conf, frequence, prediction, y_test, idx_crossval):
    """
    Save the Confidence values for each method based on user's choice. For each example in the test set (of the crossvalidation split),
    and for each method compared, this function saves one value representing the confidence of the method on the test example.

    Parameters
    ----------
    exceed_conf    : list of shape (n_test,) containing the example-wise confidence using ExCeeD (outlier probability computed by Bayesian
                     Learning with uniform prior)
    exceed_conf_sp : list of shape (n_test,) containing the example-wise confidence using ExCeeD (outlier probability computed by Bayesian
                     Learning with other prior)
    squash_conf    : list of shape (n_test,) containing the example-wise confidence using ExCeeD (outlier probability computed by squashing
                     function)
    linear_conf    : list of shape (n_test,) containing the example-wise confidence using ExCeeD (outlier probability computed by linear
                     function)
    unify_conf     : list of shape (n_test,) containing the example-wise confidence using ExCeeD (outlier probability computed by unify
                     method)
    logcal_conf    : list of shape (n_test,) containing the example-wise calibrated probability using Logistic Calibration
    isocal_conf    : list of shape (n_test,) containing the example-wise calibrated probability using Isotonic Calibration
    betacal_conf   : list of shape (n_test,) containing the example-wise calibrated probability using Beta Calibration
    frequence      : list of shape (n_test,) containing the empirical frequencies for each example in the test set
    prediction     : list of class predictions with shape (n_test,)
    y_test         : list of shape (n_test,) containing the actual labels for the test set (in crossval). It is needed for Calibration
    idx_crossval   : int representing the current fold when saving the results in the crossvalidation setting.

    Returns
    ----------
    (It only saves a file)

    """

    today = str(date.today())
    results = pd.DataFrame(data = exceed_conf, columns =['ExCeeD'])
    results['ExCeeD_sp'] = exceed_conf_otherprior
    results['Squash'] = squash_conf
    results['Linear'] = linear_conf
    results['Unify'] = unify_conf
    results['LogCal'] = logcal_conf
    results['IsoCal'] = isocal_conf
    results['BetaCal'] = betacal_conf
    results['Empirical_Freq'] = frequence
    results['Current_Pred'] = prediction
    results['Real_Label'] = y_test
    results['Fold'] = idx_crossval*np.ones(len(y_test), np.int)

    if idx_crossval == 1:
        header = True
    else:
        header = False

    results.to_csv('Confidence_Values_'+today+'.csv', mode='a', header = header) #you can change here the output path!

    return


import django.db.models.deletion
from django.db import migrations, models

class Migration(migrations.Migration):
    dependencies = [("lava_results_app", "0004_auto_20150925_0002")]

    operations = [
        migrations.AlterModelOptions(
            name="query",
            options={"verbose_name": "query", "verbose_name_plural": "queries"},
        ),
        migrations.AddField(
            model_name="query",
            name="is_archived",
            field=models.BooleanField(default=False, verbose_name="Archived"),
            preserve_default=True,
        ),
        migrations.AlterField(
            model_name="query",
            name="group",
            field=models.ForeignKey(
                on_delete=django.db.models.deletion.SET_NULL,
                default=None,
                blank=True,
                to="auth.Group",
                null=True,
            ),
            preserve_default=True,
        ),
        migrations.AlterField(
            model_name="query",
            name="query_group",
            field=models.ForeignKey(
                default=None,
                blank=True,
                to="lava_results_app.QueryGroup",
                null=True,
                on_delete=models.CASCADE,
            ),
            preserve_default=True,
        ),
    ]


# -*- coding: utf-8 -*-
from math import *

# 将弧度制转化为角度制
def radian_convert_angle(radian):  ## radian表示输入的弧度制角度
    return (radian * 180 / pi)

## 将初始角度转化为-179--180的整数
def convert_int(initial_angle):  ## initial_angle为初始角度
    if (initial_angle > -180) and (initial_angle < -179) == True:  ## 预先给无法判断的角度赋值
        c = -179
    else:
        i = -179
        while i <= 180:
            if abs(i - initial_angle) <= 0.5:  ## 四舍五入判断
                b = i
                if abs(b - initial_angle) == 0.5:  ## 中间值取进位
                    c = b + 1
                else:
                    c = b
                break  ## 退出循环
            i += 1
    return c  ## 返回整数角度

# 由节点坐标计算节点、雷达的水平方向角（结果为角度制，-179~180）
def calcu_x_direction_angle(x, y):  # x、y代表节点的横纵坐标
    if x > 0:
        if y >= 0:
            angr = atan(y / x)  ## angr为雷达水平方向角
            angn = -pi + atan(y / x)  ## angn为基站水平方向角
        else:
            angr = atan(y / x)
            angn = atan(y / x) + pi
    elif x == 0:
        if y > 0:
            angr = pi / 2
            angn = -pi / 2
        elif y < 0:
            angr = -pi / 2
            angn = pi / 2
    elif x < 0:
        if y >= 0:
            angr = atan(y / x) + pi
            angn = atan(y / x)
        else:
            angr = -pi + atan(y / x)
            angn = atan(y / x)
    angr = radian_convert_angle(angr)  # 弧度制转为角度制
    angn = radian_convert_angle(angn)
    angr = convert_int(angr)  # 角度整数化
    angn = convert_int(angn)
    return angr, angn

# 由节点到雷达的距离、节点高度、雷达高度计算节点、雷达的垂直方向角（结果为角度制，-90~90）
def calcu_y_direction_angle(d, height_nodexx, height_radarxx,
                            elevation):  # d、height_node、height_radar分别代表距离、节点高度、雷达高度、雷达仰角

    height_node = height_nodexx / 1000  # m转化为km
    height_radar = height_radarxx / 1000

    if height_node > height_radar:
        angr = atan((height_node - height_radar) / d)
        angn = -angr

    elif height_node == height_radar:
        angr = 0
        angn = 0

    elif height_node < height_radar:
        angn = atan((height_radar - height_node) / d)
        angr = -angn
    angr = radian_convert_angle(angr)  # 弧度制转为角度制
    angn = radian_convert_angle(angn)
    angr = convert_int(angr)  # 角度整数化
    angn = convert_int(angn)
    angr -= elevation  # 加入天线仰角的计算
    return angr, angn  ## angr为雷达垂直方向角,angn为基站垂直方向角

# 查表得到对应lte二维方向角的二维方向系数
def lte_calcu_direction_factor(x_angle, y_angle, lte_direction_factor):  # 参数分别代表水平方向角，垂直方向角，方向图
    for i in range(181):
        for j in range(360):
            if (y_angle + 90 == i) and (x_angle + 179 == j):
                return (lte_direction_factor[i][j])  # 返回方向系数

# 查表得到对应user二维方向角的二维方向系数
def user_calcu_direction_factor(x_angle, y_angle, user_direction_factor):  # 参数分别代表水平方向角，垂直方向角，方向图
    for i in range(181):
        for j in range(360):
            if (y_angle + 90 == i) and (x_angle + 179 == j):
                return user_direction_factor[i][j]  # 返回方向系数

# 查表得到对应radar二维方向角的二维方向系数
def radar_calcu_direction_factor(x_angle, y_angle, radar_direction_factor):  # 参数分别代表水平方向角，垂直方向角，方向图
    for i in range(181):
        for j in range(360):
            if (y_angle + 90 == i) and (x_angle + 179 == j):
                return radar_direction_factor[i][j]  # 返回方向系数

# 计算lte增益汇总函数G=D*loss_factor
def lte_gain(x, y, d, node_height, radar_height, node_loss_factor, radar_loss_factor, lte_direction_factor,
             radar_direction_factor, lte_antenna_gain, radar_antenna_gain, elevation, lte_feederline_factor,
             radar_feederline_factor):
    radar_x_angle, node_x_angle = calcu_x_direction_angle(x, y)  # 计算雷达、节点的水平方向角
    radar_y_angle, node_y_angle = calcu_y_direction_angle(d, node_height, radar_height, elevation)
    # 计算雷达、节点的垂直方向角
    radar_d_f = radar_calcu_direction_factor(radar_x_angle, radar_y_angle,
                                             radar_direction_factor)  # 计算雷达二维方向系数（db）
    node_d_f = lte_calcu_direction_factor(node_x_angle, node_y_angle,
                                          lte_direction_factor)  # 计算节点二维方向系数（db）
    final_gain = 10 * log10(
        node_loss_factor * radar_loss_factor) + radar_d_f + node_d_f + lte_antenna_gain + radar_antenna_gain \
                 - lte_feederline_factor - radar_feederline_factor
    # 总增益=最大方向增益+各角度相对增益+损耗因素
    return final_gain

# 计算user增益汇总函数G=D*loss_factor
def user_gain(x, y, d, node_height, radar_height, node_loss_factor, radar_loss_factor, user_direction_factor,
              radar_direction_factor, user_antenna_gain, radar_antenna_gain, elevation, radar_feederline_factor):
    # 参数分别为坐标、节点高度、雷达高度、节点损耗因子、雷达损耗因子、两个方向图，两个天线增益
    radar_x_angle, node_x_angle = calcu_x_direction_angle(x, y)  # 计算雷达、节点的水平方向角
    radar_y_angle, node_y_angle = calcu_y_direction_angle(d, node_height, radar_height, elevation)
    # 计算雷达、节点的垂直方向角
    radar_d_f = radar_calcu_direction_factor(radar_x_angle, radar_y_angle,
                                             radar_direction_factor)  # 计算雷达二维方向系数（db）
    node_d_f = user_calcu_direction_factor(node_x_angle, node_y_angle,
                                           user_direction_factor)  # 计算节点二维方向系数（db）
    final_gain = 10 * log10(
        node_loss_factor * radar_loss_factor) + radar_d_f + node_d_f + user_antenna_gain + radar_antenna_gain \
                 - radar_feederline_factor
    # 总增益=最大方向增益+各角度相对增益+损耗因素
    return final_gain


from DB.temp.temporary_products import TemporaryProducts
from DB.products.structured_data import StructuredProductData
from Date.get_time import date_now
from my_token import cred
import pymongo

class AllProductsDB:
    def __init__(self):
        client = pymongo.MongoClient(cred()['db_string'])
        db = client["chats"]
        self.collection = db["All Products"]

    def find_product(self, _id):
        data = self.collection.find_one({"_id": _id})
        return data

    def add_new_product(self, event):
        from_temp = TemporaryProducts().find_product(_id=event.chat.id)
        find_existing_product = self.find_product(_id=from_temp['product_code'])
        contributor = {"name": event.chat.first_name, "chat_id": event.chat_id}

        if find_existing_product is None:

            data_to_add = {'_id': from_temp['product_code'],
                           'product_code': from_temp['product_code'],
                           'product_brand': from_temp['product_brand'],
                           'URL': from_temp['URL'],
                           'discounted_price': from_temp['discounted_price'],
                           'MRP': from_temp['MRP'],
                           'total_available': from_temp['total_available'],
                           'rating': from_temp['rating'],
                           'fetched_date': from_temp['fetched_date'],
                           'fetched_time': from_temp['fetched_time'],
                           'contributors': [contributor]}

            self.collection.insert_one(data_to_add)  # Adding new data

            to_structured = {'_id': from_temp['product_code'],
                             'product_code': from_temp['product_code'],
                             'product_brand': from_temp['product_brand'],
                             'URL': from_temp['URL'],
                             'since_date': date_now()['date'],
                             'since_time': date_now()['time'],
                             'data': [{'discounted_price': from_temp['discounted_price'],
                                       'MRP': from_temp['MRP'],
                                       'total_available': from_temp['total_available'],
                                       'rating': from_temp['rating'],
                                       'fetched_date': from_temp['fetched_date'],
                                       'fetched_time': from_temp['fetched_time']}]
                             }

            StructuredProductData().add_new_product(data=to_structured)

        elif not find_existing_product is None:
            users = [_['chat_id'] for _ in find_existing_product['contributors']]

            if event.chat.id not in users:  # verifying chat.id is unique and doesn't exist in users: list
                new_value = {"$push": {'contributors': contributor}}

                # adding unique chat.id in added_by array, All products
                self.collection.update_one({"_id": find_existing_product['_id']}, new_value)

    def update_new_values(self, _id, data):
        self.collection.update_many({"_id": _id}, {"$set": data}, upsert=True)


from collections import deque

firework_effect = deque([int(x) for x in input().split(", ") if int(x) > 0])
explosive_power = [int(x) for x in input().split(", ") if int(x) > 0]
successfully_prepared = False
fireworks_dict = {"Palm Fireworks": 0, "Willow Fireworks": 0, "Crossette Fireworks": 0}
while firework_effect and explosive_power:
    firework = firework_effect.popleft()
    power = explosive_power.pop()
    result = firework + power
    if result % 3 == 0 and result % 5 != 0:
        fireworks_dict["Palm Fireworks"] += 1
    elif result % 5 == 0 and result % 3 != 0:
        fireworks_dict["Willow Fireworks"] += 1
    elif result % 3 == 0 and result % 5 == 0:
        fireworks_dict["Crossette Fireworks"] += 1
    else:
        if firework - 1 > 0:
            firework_effect.append(firework - 1)
        explosive_power.append(power)
    if fireworks_dict["Palm Fireworks"] >= 3 and fireworks_dict["Willow Fireworks"] >= 3 \
            and fireworks_dict["Crossette Fireworks"] >= 3:
        successfully_prepared = True
        break

if successfully_prepared:
    print("Congrats! You made the perfect firework show!")
else:
    print("Sorry. You can't make the perfect firework show.")

if firework_effect:
    print(f"Firework Effects left: {', '.join([str(x) for x in firework_effect])}")
if explosive_power:
    print(f"Explosive Power left: {', '.join([str(x) for x in explosive_power])}")

for key, value in fireworks_dict.items():
    print(f"{key}: {value}")


#!/usr/bin/env python
# -*- coding: utf-8 -*-

NCORE = 6
execfile('/home/feng/meta/header_0903.py')
figs = pyutil.collections.OrderedDict()

url = 'http://172.26.114.34:81/static/figures/0122__prepareRNA__CAMICE/tracks.npy'
tracks = pyutil.readData(url).tolist()
tdf =tracks.cold_wt

import pymisca.model_collection.mixture_vmf as mod

if 1:
    data = tdf
    randomState = 0
    np.random.seed(randomState)
    nIter = 1600
    nStart = 1
#     betas = lambda i: (i + 1) * 0.00015 + 0.15
    callback = mod.callback__stopAndTurn(
        start=0.1,
        step=(10.0-0.1)/nIter)
#     callback = pyfop.composeF(callback__stopAndTurn(betas=betas),
# #                              callback__stopOnClu(interval=1)
#                              )
    mdl0 = mdl = mod.MixtureVMF(init_method = 'random',
                        NCORE=1,
#                          beta = betas(0),
                         weighted =  True,
                         normalizeSample=0,
                        kappa = None,
                        K = 20,)
    res = mdl.fit(
        data,verbose=2,
                  nStart=nStart,
                  callback = callback,
                  min_iters = nIter,
                  max_iters = nIter,
                  sample_weights=None,
                 )
    np.save('mdl.npy',mdl0,)

mod.qc__vmf(mdl0)
figs['qcVMF'] = plt.gcf()
execfile('/home/feng/meta/footer__script2figure.py')

mdl = mdl0.callback.mdls[nIter//2][-1]
cacheFile = pyutil.cache__model4data(mdl=mdl,tdf=data,ofname='modelCache.npy')


#!/usr/bin/env python3

import PCA_old
import con_traj
import sys
import kss_time_scale
import autocorr
import eigenvecdot
import lipic
import proj_dist_s
import pearson
import proj_parse
import visualizing
import PCA
import project
import projdistm
import eigenvalues
import combtraj
import reltime
import timescalespic
import argparse
import overlap

# Basic option class
# Needed to select correct function to continue
class Option:
    def __init__(self,func=str,fname=str,optList=list,description=""):
        self.func        = func
        self.fname       = fname
        self.optList     = optList
        self.description = description

# Function option class
# Needed to parse the input parameters for function
class OptionF:
    def __init__(self,func=str,num=1,default=None,description=""):
        self.func        = func
        self.num         = num
        self.value       = default
        self.description = description
    def __nonzero__(self):
        return self.value != None
    def __str__(self):
        return self.value and str(self.value) or ""
    def setvalue(self,v):
        if len(v) == 1:
            self.value = self.func(v[0])
        else:
            self.value = [ self.func(i) for i in v ]

def main(args):

	optionsConcat = [
	# options for concat feature
	"Input/output options for concat feature",
	("-f", OptionF(str, 1, None, "Input trajectory file (.xtc, .trr, ...)")),
	("-t", OptionF(str, 1, None, "Input topology file (.pdb, .gro, ...)")),
	("-stride", OptionF(int, 1, 1, "Only read every Nth frame")),
	("-sf", OptionF(int, 1, 0, "First frame (ps) to read from trajectory")),
	("-ef", OptionF(int, 1, -1, "Last frame (ps) to read from trajectory")),
	("-oc", OptionF(str, 1, "concatenated.xtc", "Output concatenated trajectory file")),
	("-oa", OptionF(str, 1, "average.pdb", "Output average structure")),
	("-r", OptionF(str, 1, None, "Input reference file (.pdb, .gro). If not supplied, \
the structure of the first lipid and the first frame is used for alignment")),
	("-l", OptionF(str, 1, None, "Lipid type")),
	("-sel", OptionF(str, 1, "", "Lipid selection"))
	]

	optionsConspace = [
	# options for conspace feature
	"Input/output options for conspace feature",
	("-f", OptionF(str, 1, None, "Input XTC or TRR file")),
	("-t", OptionF(str, 1, None, "Input topology PDB of GRO file")),
	("-stride", OptionF(int,1,1000, "Only read every Nth frame (default: 1000)")),
	("-om", OptionF(str, 1, "conformations.pdb", "Output PDB file with conformations")),
	("-al", OptionF(int, 1, 0, "Is align needed (0: no; 1: yes; default: 0)"))
	]

	optionsCovar = [
	# options for covar feature
	"Input/output options for covar feature",
	("-f", OptionF(str, 1, None, "Input XTC or TRR concatenated trajectory")),
	("-t", OptionF(str, 1, None, "Input topology PDB of GRO file")),
	("-oeval", OptionF(str, 1, "eigenval.xvg", "Eigenvalue output file")),
	("-oevec", OptionF(str, 1, "eigenvec.xvg", "Eigenvector output file")),
	("-ocov", OptionF(str, 1, "covar.dat", "Covariance matrix output file"))
	]

	optionsProject = [
	# options for project feature
	"Input/output options for project feature",
	("-f", OptionF(str, 1, None, "Input XTC or TRR concatenated trajectory")),
	("-t", OptionF(str, 1, None, "Input topology PDB of GRO file")),
	("-ia", OptionF(str, 1, None, "PDB of GRO file for average structure")),
	("-ievec", OptionF(str, 1, None, "Eigenvector input file")),
	("-first", OptionF(int, 1, 1, "First PC for projection (default: 1)")),
	("-last", OptionF(int, 1, 10, "First PC for projection (default: 10)")),
	("-op", OptionF(str, 1, "proj.xvg", "Output projection files name\n\
		Do not use '-' or '.' symbols in the projection file names"))
	]

	optionsMotion = [
	# option for motion feature
	"Input/output options for motion feature",
	("-p", OptionF(str, 1, None, "Input projection file")),
	("-aver", OptionF(str, 1, None, "PDB of GRO file for average structure")),
	("-ievec", OptionF(str, 1, None, "Eigenvector input file")),
	("-eo", OptionF(str, 1, "extreme.pdb", \
		"PDB file name with a motion for selected PC"))
	]

	optionsProjDist = [
	# options for projdist feature
	"Input/output options for projdist feature",
	("-p", OptionF(str, 1, None, "Input projection file")),
	("-pr", OptionF(str, 1, None, "Range of input projection files: \n\
	example: -pr proj_1.xvg-proj_10.xvg"))
	]

	optionsAutot = [
	# options for autot feature
	"Input/output options for autot feature",
	("-p", OptionF(str, 1, None, "Input projection file")),
	("-pr", OptionF(str, 1, None, "Range of input projection files: \n\
	example: -pr proj_1.xvg-proj_10.xvg")),
	("-ln", OptionF(int, 1, 1, "Number of lipids in the system (default: 1)")),
	("-dt", OptionF(float, 1, 0.01, "Timestep (ns) (default: 0.01 ns)")),
	("-o", OptionF(str, 1, "acor.xvg", "Name of output files"))
	]

	optionsKsst = [
	# options for ksst feature
	"Input/output options for ksst feature",
	("-p", OptionF(str, 1, None, "Input projection file")),
	("-pr", OptionF(str, 1, None, "Range of input projection files: \n\
	example: -pr proj_1.xvg-proj_10.xvg")),
	("-ln", OptionF(int, 1, 1, "Number of lipids in the system (default: 1)")),
	("-dt", OptionF(float, 1, 0.01, "Timestep (ns) (default: 0.01 ns)")),
	("-o", OptionF(str, 1, "kss.xvg", "Name of output files"))
	]

	optionsCombtrajs = [
	# options for combtrajs feature
	"Input/output options for combtrajs feature",
	("-fs", OptionF(str, -1, None, \
		"Input trajectories and corresponding average structures")),
	("-ou", OptionF(str,1,"united.xtc","Output combined trajectory")),
	("-oc", OptionF(str,1,"concatenated.xtc",\
		"Aligned trajectories for different simulations")),
	("-oa", OptionF(str,1,"average.pdb","Output average structures"))
	]

	optionsPearson = [
	# options for pearson feature
	"Input/output options for pearson feature",
	("-cov1", OptionF(str,1,None,"Covariance matrix for the first trajectory")),
	("-cov2", OptionF(str,1,None,"Covariance matrix for the second trajectory")),
	("-o", OptionF(str,1,"pearson.dat","Output file")),
	"Pearson correlation coeficient is shown in the terminal and saved to the output file"
	]

	optionsOverlap = [
	# options for pearson feature
	"Input/output options for overlap feature",
	("-cov1", OptionF(str,1,None,"Covariance matrix for the first trajectory")),
	("-cov2", OptionF(str,1,None,"Covariance matrix for the second trajectory")),
	("-o", OptionF(str,1,"overlap.dat","Output file")),
	"Overlap of the conformational spaces as introduce in https://doi.org/10.1103/PhysRevE.65.031910 \n\
	is shown in the terminal and saved to the output file"
	]

	optionsEigenvecdot = [
	# options for eigenvecdot feature
	"Input/output options for evecdot feature",
	("-evec", OptionF(str,2,None,"Input eigenvectors for 2 simulations")),
	("-o", OptionF(str,1,"eigenvecproduct.xvg","Output file name"))
	]

	optionsProjdistM = [
	# options for projdistm feature
	"Input/output options for projdistm feature",
	("-files", OptionF(str,-1,None,"Input projection files")),
	("-o", OptionF(str,1,"distributions.png","Output file name"))
	]

	optionsTimescalespic = [
	# options for timescalespic feature
	"Input/output options for timescalespic feature",
	("-file1", OptionF(str,-1,None,"Input timescales for 1st simulation")),
	("-file2", OptionF(str,-1,None,"Input timescales for 2nd simulation")),
	("-type", OptionF(str,1,"auto","auto for autocorrelation timescales;\n\
	kss for distribution convergence timescales")),
	("-t",  OptionF(str,-1,"t2",'t1" or "t2" for selected \n\
	timescale measure decay in e or e^2 times')),
	("-o", OptionF(str,1,"timescales_comp.png","Output file name"))
	]

	optionsReltime = [
	# options for reltime feature
	"Input/output options for reltime feature",
	("-eval",OptionF(str,1,None,"Eigenvalue file for base simulation")),
	("-time1",OptionF(str,1,None,"characteristic timescales for 1st simulation")),
	("-time2",OptionF(str,1,None,"characteristic timescales for 2nd simulation")),
	("-o",OptionF(str,1,"tsCmp.dat","Output file"))
	]

	optionsEvals = [
	# options for evals feature
	"Input/output options for evals feature",
	("-ieval", OptionF(str,1,None,"Eigenvalue file for simulation")),
	("-cum", OptionF(int,1,0,"Plot cumulative (or just) eigenvalues 1(0). default: 0")),
	("-o",OptionF(str,1,"eval.png","Output file"))
	]

	options = [
	# list of all available features
	"List of procedures\n",
	"Performing PCA on lipid molecule conforamtions\n",
	("concat", Option(str,"con_traj",optionsConcat,\
		"Concatenate trajectories of individual lipids")),
	("conspace", Option(str,"lipic",optionsConspace,\
		"Vizualize possible conformations for concatenated trajectory")),
	("covar", Option(str,"PCA",optionsCovar,\
		"Perform PCA on aligned concatenated lipid trajectory")),
	("evals", Option(str,"eigenvalues",optionsEvals,\
		"Plot eigenvalues for calculated PCs")),
	("project", Option(str,"project",optionsProject,\
		"Project concatenated lipid trajectory on the calculated PCs")),
	("motion", Option(str,"visualizing",optionsMotion,\
		"Create pdb file that represents the motion along selected PC")),
	("projdist", Option(str,"proj_dist_s",optionsProjDist,\
		"Plot projection distributions for selected PCs")),
	"\nCalculating characteristic timescales\n",
	("autot", Option(str,"autocorr",optionsAutot,\
		"Calculate autocorrelation decay times")),
	("ksst", Option(str,"kss_time_scale",optionsKsst,\
		"Calculate distribution convergence times")),
	"\nComparing several trajectories\n",
	("combtrajs", Option(str,"combtraj",optionsCombtrajs,\
		"Combine two trajectories")),
	("pearson", Option(str,"pearson",optionsPearson,\
		"Compare covariance matrices from two simulations")),
	("overlap", Option(str,"overlap",optionsOverlap,\
		"Compare covariance matrices from two simulations")),
	("evecdot", Option(str,"eigenvecdot",optionsEigenvecdot,\
		"Compare eigenvectors from two simulations")),
	("projdistm", Option(str,"projdistm",optionsProjdistM,\
		"Plot projection distributions for simulations of interest")),
	("tsCmpFig", Option(str,"timescalespic",optionsTimescalespic,\
		"Plot timescales for two trajectories")),
	("reltime", Option(str,"reltime",optionsReltime,\
		"Compare characteristic timescales for two trajectories"))
	]

	# Short description of the software
	desc = """
   PCAlipids is a software for analysis of lipid
   molecule conformations and dynamics.
   You could find more information on the software usage at:
      https://github.com/membrane-systems/PCAlipids
   In case of usage for your research please cite:
   1. [Principal Component Analysis of Lipid Molecule Conformational
   Changes in Molecular Dynamics Simulations, Buslaev et al., JCTC 2016]
   2. [Effects of Coarse Graining and Saturation of Hydrocarbon
   Chains on Structure and Dynamics of Simulated Lipid Molecules,
   Buslaev & Gushchin, Sci. Rep. 2017]
	"""

	# If the user asks for help: pcalipids.py -h
	if (len(args)>0 and (args[0] == '-h' or args[0] == '--help')) or len(args)==0:
		print("\n",__file__[__file__.rfind('/')+1:]) # print executable file name
		print(desc) # print description !!! we need to create a good one
		for thing in options: # print all options
			print(type(thing) != str and "%10s: %s"%(thing[0],thing[1].description) or thing)
		print()
		sys.exit()

	# Create a dictionary from options
	# All strings are ignored (they descriptive)
	options = dict([i for i in options if not type(i) == str])

	# Redirect main to the correct import class
	main = globals()[options[args[0]].fname].main
	funcname=args[0]
	optionsF = options[args[0]].optList

	# We don't need 0 argument of args any more
	args = args[1:]

	# if the user asks for help: pcalipids.py concat -h
	if (len(args)>0 and (args[0] == '-h' or args[0] == '--help')) or len(args)==0:
		print("\n",__file__[__file__.rfind('/')+1:],\
			funcname+": "+options[funcname].description) # print executable file name
		print(desc) # print description !!! we need to create a good one
		for thing in optionsF: # print all options for selected feature
			print(type(thing) != str and "%10s: %s"%(thing[0],thing[1].description) or thing)
		print()
		sys.exit()

	# Create a dictionary with possible arguments for the selected feature
	optionsF = dict([i for i in optionsF if not type(i) == str])

	# Parsing argumens and setting values
	while args:
		ar = args.pop(0) # choose argument
		if optionsF[ar].num == -1:
			listOfInputs = []
			while args:
				ar1 = args.pop(0)
				if ar1 in list(optionsF.keys()):
					optionsF[ar].setvalue(listOfInputs)
					args.insert(0,ar1)
					break
				else:
					listOfInputs.append(ar1)
			optionsF[ar].setvalue(listOfInputs)
		else:
			optionsF[ar].setvalue([args.pop(0) for i in range(optionsF[ar].num)]) # set value

	# Pass all the parameters to function
	params=list(v.value for v in optionsF.values())
	main(*params)

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


import numpy as np
import matplotlib.pyplot as plt

from typing import List, Dict
from scipy import special, stats
from sklearn.calibration import calibration_curve

#== probs conversion functions ====================================================================#
def probs_to_logits(probs:dict)->dict:
    output = {}
    for idx, prob in probs.items():
        logits = np.log(prob)
        output[idx] = logits
    return output

def probs_to_entropies(probs:dict)->dict:
    output = {}
    for idx, ex_prob in probs.items():
        entropy = _calc_entropy(ex_prob)
        output[idx] = entropy
    return output

def probs_to_preds(probs:dict)->dict:
    preds = {}
    for ex_id, probs in probs.items():
        preds[ex_id] = int(np.argmax(probs, axis=-1))
    return preds

def _calc_entropy(prob_np:np.ndarray):
    return stats.entropy(prob_np, base=2, axis=-1)

def anneal_probs(probs:dict, labels:dict)->dict:
    def anneal_prob(ex_prob, alpha):
        ex_logits = np.log(ex_prob)
        ex_logits /= alpha
        ex_prob = special.softmax(ex_logits, axis=-1)
        return ex_prob

    probs_np = convert_dict_np(probs)
    labels_np = convert_dict_np(labels)

    _, alpha = anneal_probs_np(probs_np, labels_np)
    an_probs = {idx:anneal_prob(prob, alpha) for idx, prob in probs.items()}
    return an_probs

#== numpy helper functions ========================================================================#
def convert_dict_np(input_dict:Dict[str, np.ndarray])->np.ndarray:
    output = []
    for k, p in sorted(input_dict.items()):
        output.append(p)
    output = np.array(output)
    return output

def probs_to_preds_np(probs_np:np.ndarray)->np.ndarray:
    return np.argmax(probs_np, axis=-1)

def get_hits_np(preds_np:np.ndarray, labels_np:np.ndarray):
    return preds_np == labels_np

def calc_entropy_np(probs_np:np.ndarray)->np.ndarray:
    return stats.entropy(probs_np, base=2, axis=-1)

def calc_confidence_np(probs_np:np.ndarray)->np.ndarray:
    return np.max(probs_np, axis=-1)

def anneal_probs_np(probs_np:np.ndarray, labels_np:np.ndarray):
    #get current model probs and avg max prob
    logits = np.log(probs_np)
    max_probs_np = [max(i) for i in probs_np]
    avg_prob = np.mean(max_probs_np)

    #look at current model accuracy
    preds = probs_to_preds_np(probs_np)
    hits = get_hits_np(preds, labels_np)
    acc = np.mean(hits)

    #do the annealing
    alpha = 1
    while avg_prob > acc:
        alpha += 0.001
        annealed_logits = logits/alpha
        probs_np  = special.softmax(annealed_logits, axis=-1)
        max_probs = [max(i) for i in probs_np]
        avg_prob = np.mean(max_probs)
    return probs_np, alpha

#== plotting functions ============================================================================#
def entropy_plot(probs:dict, labels:dict=None, ax1=None, ax2=None, color='blue', calibrate=False):
    """ get effective number of options distribution """

    #create axis if not provided
    if ax1 is None and ax2 is None:
        fig, ax1 = plt.subplots(figsize=(12,8))
        if labels: ax2 = ax1.twinx()
        plt.ylim(0)

    # convert dicts to numpy array
    probs = convert_dict_np(probs)
    preds = probs_to_preds_np(probs)

    # load labels, and calibrate model if needed
    if labels:
        labels = convert_dict_np(labels)
        hits = get_hits_np(preds, labels)
        if calibrate: probs, _ = anneal_probs_np(probs, labels)

    # calculate entropy and effective number of options
    entropies = calc_entropy_np(probs)
    eff_num_opt = 2**entropies

    # binning points and calculating accuracies
    bins = [i/100 for i in range(100,401, 20)]
    hist, bin_edges = np.histogram(eff_num_opt, bins=bins)
    bin_centres = np.array(bins[:-1]) + 0.1

    # plotting
    ax1.plot(bin_centres, hist, marker='.', color=color, linewidth=4, markersize=18)

    # get accuracies for bins, if labels are available, and plot
    if labels:
        probs_c = [prob for prob, hit in zip(probs, hits) if hit==1]
        entropies_c = calc_entropy_np(probs_c)
        eff_num_opt_c = 2**entropies_c
        hist_c, _ = np.histogram(eff_num_opt_c, bins=bins)
        accuracies  = np.array(hist_c)/np.array(hist)
        ax2.plot(bin_centres, accuracies, marker='.', linestyle=(0, (3, 1, 1, 1)), color=color, linewidth=4, markersize=18)

def calibration_plot(probs:dict, labels:dict=None, ax=None, color='blue', n_bins=10):
    #create axis if not provided
    if ax is None:
        fig, ax = plt.subplots(figsize=(12,8))

    # get confidence
    probs_np = convert_dict_np(probs)
    conf_np = calc_confidence_np(probs_np)

    #get if example was correct or not
    preds_np = probs_to_preds_np(probs_np)
    labels_np = convert_dict_np(labels)
    hits_np = get_hits_np(preds_np, labels_np)

    # Plot model's calibration curve
    prob_true, prob_pred = calibration_curve(hits_np, conf_np, n_bins)
    ax.plot(prob_true, prob_pred, marker = '.')

    # Plot perfectly calibrated
    ax.plot([0, 1], [0, 1], linestyle = '--', label = 'Ideally Calibrated')

#== probs conversion functions ====================================================================#
def probs_to_distractor_entropies(probs:dict, labels:dict)->dict:
    """ gets entropies at the distractor level"""
    assert probs.keys() == labels.keys()

    logits = probs_to_logits(probs)

    output = {}
    for idx in sorted(labels.keys()):
        ex_logits = logits[idx]
        answer = labels[idx]

        for k in range(len(ex_logits)):
            # skip correct answer
            if k == answer: continue
            dist_prob = special.softmax([ex_logits[answer], ex_logits[k]])
            output[(idx,k)] = stats.entropy(dist_prob)

    return output


from base_page import BasePage
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains

'''
The Jisho header exists across all Jisho pages with common functions
so all pages should extend from this one. This class shouldn't be used
for testing but rather a way to create further Jisho page objects
'''
class JishoHeader(BasePage):
    url = 'https://jisho.org'
    ''' CSS selectors for this page '''
    logo_link = '.logo a'
    search_input = '#keyword'
    handwriting_button = '#handwriting_button'
    handwriting_pad = '.panel canvas'
    handwriting_results = '#handwriting_area a.result'
    radical_button = '#radical_button'

    def click_logo_image(self):
        self.wait_for_element(self.logo_link).click()

    def set_search_bar_text(self, kanji):
        search_element = self.wait_for_element(self.search_input)
        # This should probably be encoded unicode?
        search_element.send_keys(kanji)

    def get_search_bar_text(self):
        return self.wait_for_element(self.search_input).get_attribute('value')

    def search_via_enter_button(self):
        search_element = self.wait_for_element(self.search_input)
        # press enter afterwards
        search_element.send_keys('\ue007')

    def open_handwriting_pad(self):
        handwriting_button = self.wait_for_element(self.handwriting_button)
        handwriting_button.click()

    def draw_on_handwriting_pad(self, points_list):
        ''' Take in a list of lists of points corresponding to drawn lines '''
        for vertex_list in points_list:
            line_drawer = ActionChains(self.driver)
            # get handwriting pad element
            handwriting_pad = self.wait_for_element(self.handwriting_pad)
            # navigate to first point and remove it from the list
            initial_x, initial_y = vertex_list.pop(0)
            line_drawer.move_to_element(handwriting_pad)
            line_drawer.move_to_element_with_offset(handwriting_pad, initial_x, initial_y)
            # click and hold
            line_drawer.click_and_hold()
            # move mouse to remaining points
            for x, y in vertex_list:
                line_drawer.move_to_element_with_offset(handwriting_pad, x, y)
            # release
            line_drawer.release()
            line_drawer.perform()
        pass

    def get_handwriting_results(self):
        all_kanji = self.wait_for_elements(self.handwriting_results)
        return list(map(lambda x: x.text, all_kanji))


import os
import shutil
import re

# Define the directories
code_dir = "C:\\Users\\jajohns\\Files\\Publishing\\open_principles_of_microeconomics\\open_principles_of_microeconomics_dev"
doctomd_dir = os.path.join(code_dir, "doctomd")
media_dir = os.path.join(doctomd_dir, "media")
target_dir = os.path.join(code_dir, "QMD_open_principles_of_microeconomics")

# Copy the media folder
shutil.copytree(media_dir, os.path.join(target_dir, "media"), dirs_exist_ok=True)
print("Media folder copied.")

# Regular expression patterns for the desired .md files
patterns = [
    re.compile(r"^\d+-\d+-.+\.md$"),  # Number-number-title.md
    re.compile(r"^\d+-introduction-.+\.md$"),  # number-introduction-title.md
    re.compile(r"^1-introduction\.md$")  # Exact match for 1-introduction.md
]

# Copy and rename .md files to .qmd
for filename in os.listdir(doctomd_dir):
    if any(pat.match(filename) for pat in patterns):
        md_file_path = os.path.join(doctomd_dir, filename)
        qmd_file_path = os.path.join(target_dir, os.path.splitext(filename)[0] + ".qmd")

        shutil.copy(md_file_path, qmd_file_path)
        print(f"Copied and renamed {filename} to {qmd_file_path}")

print("All specified .md files have been copied and renamed to .qmd.")


import socket
import sys

# Create socket that allows two comps to connect

def socket_create():
    try:
        global host
        global port
        global sock
        host = ''
        port = 9999
        sock = socket.socket()
    except socket.error as msg:
        print("Socket error" + str(msg))

# Bind socket to the port and wait for connection

print(socket.gethostbyname(socket.gethostname()))

def socket_bind():
    try:
        global host
        global port
        global sock
        print("Binding socket to the port " + str(port))
        sock.bind((host, port))
        sock.listen(5)

    except socket.error as msg:
        print("Socket binding error" + str(msg) + '\n' + 'Retrying...')
        socket_bind()

# Establish connection

def socket_accept():
    conn, address = sock.accept()
    print('Connection has been established \n IP: ' + address[0]
          + '\nPort: ' + str(address[1]))
    send_commands(conn)
    conn.close()

# Send commands

def send_commands(conn):
    while True:
        cmd = input()
        if cmd == 'quit':
            conn.close()
            sock.close()
            sys.exit()

        if len(str.encode(cmd)) > 0:
            conn.send(str.encode(cmd))
            client_response = str(conn.recv(1024), encoding='utf-8')
            print(client_response, end="")

def main():
    socket_create()
    socket_bind()
    socket_accept()

main()


from graph import Graph, Node, REFERENCE_PATH_INDEX
import re

def parse_reference_genome(filename):
	lines = open(filename, 'r').readlines()
	header = lines[0];
	id, description, species = parse_FASTA_header(header)
	graph = Graph(id, description, species)
	parse_FASTA_lines(graph, lines[1:])

	return graph

def parse_FASTA_header(header):
	tokens = header.split(" ")
	id = tokens[0][1:]

	description = 'Unknown description'
	species = 'Unknown species'
	description = header[len(id) + 2:].strip()
	try:
		species = description.split('[')[1][:-1]
	except:
		print('Unable to parse entire fasta header')

	return id, description, species

def parse_FASTA_lines(graph, lines):
	curr = graph.head
	index = 1
	for line in lines:
		for character in line:
			if character != '\n':
				next = Node(character, index)
				graph.add_node(next)
				curr.add_neighbour(next, REFERENCE_PATH_INDEX)
				index += 1
				curr = curr.get_neighbour_by_index(0)
	curr.add_neighbour(graph.tail, REFERENCE_PATH_INDEX)
	graph.current_index = index

	return graph

def parse_VCF_variants(graph, filename):
	lines = open(filename, 'r').readlines()
	headers, data = split_VCF(lines)
	for line in data:
		parse_VCF_variant(graph, line)

def split_VCF(lines):
	headers = []
	data = []
	for line in lines:
		if (line[0] == "#"):
			headers.append(line)
		else:
			data.append(line)

	return headers, data

def parse_VCF_variant(graph, line):
	if (line[0] == '#'):
		return

	tokens = re.split(r'\s+', line)
	index = int(tokens[1])
	path = tokens[2]
	original = tokens[3]
	variants = tokens[4]

	for variant in variants.split(","):
		handle_variant(graph, original, variant, index, path)

def handle_variant(graph, original, value, index, path):
	print('Handling variant ' + original + ' -> ' + value + ' on index ' + str(index))
	type = get_variant_type(original, value)
	if (type == VARIANT_TYPE_SNP):
		graph.add_SNP(value, index, path)
	elif (type == VARIANT_TYPE_INSERTION):
		graph.add_insertion(value, index, path)
	elif (type == VARIANT_TYPE_DELETION):
		graph.add_deletion(len(original) - len(value), index, path)
	elif (type == VARIANT_TYPE_COMPLEX):
		graph.add_short_insertion(original, value, index, path)
	else:
		print('Not implemented variant handling on the form ' + original + ', ' + value)

VARIANT_TYPE_SNP = 0
VARIANT_TYPE_INVALID = 1
VARIANT_TYPE_DELETION = 2
VARIANT_TYPE_INSERTION = 3
VARIANT_TYPE_COMPLEX = 4
VARIANT_TYPE_OTHER = 5

def get_variant_type(original, value):
	if (len(original) == 1 and len(value) == 1):
		return VARIANT_TYPE_SNP
	elif (len(original) < 1 or len(value) < 1):
		return VARIANT_TYPE_INVALID
	elif (len(original) > len(value)):
		if (original[0:len(value)] == value):
			return VARIANT_TYPE_DELETION
		else:
			return VARIANT_TYPE_COMPLEX
	elif (len(value) > len(original)):
		if (value[0:len(original)] == original):
			return VARIANT_TYPE_INSERTION
		else:
			return VARIANT_TYPE_COMPLEX
	else:
		return VARIANT_TYPE_OTHER

def parse_global_alignment(filename):
	lines = open(filename, 'r').readlines()
	pairs = []

	i = 2
	while (i < len(lines)):
		if (len(lines[i].split()) == 0):
			pairs.append([lines[i - 2].split()[2], None])
			i += 3
		else:
			pairs.append([lines[i - 2].split()[2], lines[i].split()[2]])
			i += 4

	alignment1 = ''
	alignment2 = ''
	start = True
	for pair in pairs:
		alignment1 += pair[0]
		if not pair[1]:
			for i in range(0, len(pair[0])):
				alignment2 += '-'
		elif len(pair[0]) > len(pair[1]):
			if start:
				for i in range(0, len(pair[0]) - len(pair[1])):
					alignment2 += '-'
				alignment2 += pair[1]
				start = False
			else:
				alignment2 += pair[1]
				for i in range(0, len(pair[0]) - len(pair[1])):
					alignment2 += '-'
		else:
			alignment2 += pair[1]
			start = False

	name = filename
	if (len(name.split('/')) > 1):
		name = name.split('/')[-1]
	return filename, alignment1, alignment2

def write_left_right_index_to_file(index, filename):
	left_contexts = index.left_contexts
	right_contexts = index.right_contexts

	writer = open(filename, 'w')
	writer.write('left_context#' + str(len(left_contexts)) + '\n')
	for context in left_contexts:
		writer.write(context['context'] + '#' + str(context['index']) + '\n')
	writer.write('\nright_context#' + str(len(right_contexts)) + '\n')
	for context in right_contexts:
		writer.write(context['context'] + '#' + str(context['index']) + '\n')

	writer.close()


import os
import argparse
import subprocess
import pickle
import time

import numpy as np

RESULT_DIR="./result"

# too old, not maintain

def gpu_run(gpu, thread, tile_size, block_power_max=12, buffer_size_max=48, dataset="ADS2"):
  data = {}
  data['block_size'] = []
  data['buffer_size'] = []
  data['gflops'] = np.zeros(shape=(block_power_max + 1, buffer_size_max))
  data['bw'] = np.zeros(shape=(block_power_max + 1, buffer_size_max))
  data['prep_time'] = np.zeros(shape=(block_power_max + 1, buffer_size_max))
  data['time'] = np.zeros(shape=(block_power_max + 1, buffer_size_max))

  start = time.time()
  for i, block_power in enumerate(range(0, block_power_max + 1)):
    block_size = 2 ** block_power
    data['block_size'].append(block_size)
    for j, buffer_size in enumerate(range(1, buffer_size_max + 1)):
      data['buffer_size'].append(buffer_size)
      cmd = "./run.gpu.sh {} {} {} {} {} {}".format(gpu, thread, dataset, tile_size, block_size, buffer_size)
      print("GPU for tile_size: {}, block_size: {}, buffer_size: {}, dataset: {}".format(tile_size, block_size, buffer_size, dataset))
      print("\tcmd: {}".format(cmd))
      process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
      stdout, _ = process.communicate()
      process.wait()

      li = stdout.decode().strip().split(',')
      assert len(li) == 4
      gflops, bw, prep_time, tot_time = float(li[0]), float(li[1]), float(li[2]), float(li[3])
      data['gflops'][i][j] = gflops
      data['bw'][i][j] = bw
      data['prep_time'][i][j] = prep_time
      data['time'][i][j] = tot_time

  end = time.time()
  pickle.dump(data, open("result/{}.gpu.pkl".format(tile_size), "wb"))
  print("Done Time: {} sec", end - start)

if __name__ == "__main__":
  parser = argparse.ArgumentParser()
  parser.add_argument("--gpu", "-gpu", required=True, type=str, dest="gpu", help="gpu")
  parser.add_argument("--thread", "-thread", required=True, type=int, dest="thread", help="thread")
  parser.add_argument("--tile_size", "-tile", required=True, type=int, dest="tile_size", help="tile_size")
  #parser.add_argument("--block_size", "-block", dest="block_size", help='block size')
  #parser.add_argument("--buffer_size", "-buf", dest="buffer_size", help='buffer size')

  args = parser.parse_args()
  gpu_run(args.gpu, args.thread, args.tile_size)


"""Module om met DHT20 sensoren de temperatuur en vochtigheid te meten en vast te leggen in een DB.
"""

from typing import Tuple
import time
import smbus2

# from Modules.DB_write import log_temp_humid

def get_temp_and_humid() -> Tuple[float, float]:
    """Meet de temperatuur en luchtvochtigheid middels een DHT20 sensor.

    Returns:
        Tuple[float, float]: De gemeten waarden als (temperatuur, luchtvochtigheid).
    """

    address = 0x38  # DHT20 address: sudo i2cdetect -y 1

    i2cbus = smbus2.SMBus(1)
    time.sleep(0.5)

    data = i2cbus.read_i2c_block_data(address, 0x71, 1)
    if (data[0] | 0x08) == 0:
        print('Initialization error')

    i2cbus.write_i2c_block_data(address, 0xac, [0x33, 0x00])
    time.sleep(0.1)

    data = i2cbus.read_i2c_block_data(address, 0x71, 7)

    Traw = ((data[3] & 0xf) << 16) + (data[4] << 8) + data[5]
    temperature = 200 * float(Traw) / 2**20 - 50

    Hraw = ((data[3] & 0xf0) >> 4) + (data[1] << 12) + (data[2] << 4)
    humidity = 100 * float(Hraw) / 2**20

    print(f"Temp: {temperature:.1f}°C, humid {humidity:.1f}%.")
    return temperature, humidity

if __name__ == "__main__":
    temp, humid = get_temp_and_humid()
    # print(f"Temp: {temp:.1f}, humid {humid:.1f}.")


import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf

import tensorflow_datasets as tfds

import os

from PIL import Image

ds_train, info = tfds.load("coco", split = "train", shuffle_files = True, with_info= True)
ds_val, info = tfds.load("coco", split = "validation", shuffle_files = True, with_info= True)
ds_test, info = tfds.load("coco", split = "test", shuffle_files = True, with_info= True)

labels = info.features["objects"]["label"].names

subset_names = ['baseball bat', 'baseball glove', 'frisbee', 'kite', 'skateboard', 'skis', 'snowboard', 'sports ball', 'surfboard', 'tennis racket']
subset_ids = [34, 35, 29, 33, 36, 30, 31, 32, 37, 38]

def get_subset_ids():
    ids = []

    for label in subset_names:
        for index, big_label in enumerate(labels):
            if label == big_label:
                ids.append(index)

    return ids

LABEL_SUBSET = {id: name for id, name in zip(subset_ids, subset_names)}
ROOT_DIR = "/home/ec2-user/Documents/datasets/coco_sports/"

# Filter out examples that don't have a label in the label subset

def preprocess_data(dataset, split_name):
    '''
    Preprocesses the dataset by filtering out examples that don't have a label in the label subset
    and cropping the images to only include the object they are labeled with

    Params:
        dataset: the dataset to preprocess
        split_name: the name of the split to create a directory for

    Returns:
        None

    Side Effects:
        Creates a directory to hold the split and a directory in it to hold each class
        Saves the cropped images to the appropriate class directory
    '''

    # Create a directory to hold this split and a directory in it to hold each class
    split_directory = create_directories(split_name)

    # Filter out any images that are labeled with something in the subset
    # Crop them to only include the object they are labeled with
    # Save them

    for example in dataset:
        if within_subset(example):
            crop_and_save(example, split_directory)

def within_subset(example):
    '''
    Returns True if the example has a label in the subset
    '''
    labels = example["objects"]["label"].numpy()

    for label in labels:
        if label in LABEL_SUBSET.keys():
            return True

    return False

def crop_and_save(example, split_directory):
    '''
    Crops the image to only include the object it is labeled with and saves it to the appropriate class directory

    Params:
        example: the example to crop and save
        split_directory: the directory to save the cropped image to

    Returns:
        None

    Side Effects:
        Saves the cropped image to the appropriate class directory
    '''
    # Find the first label on the example that is in the label subset
    labels = example["objects"]["label"].numpy()
    index = -1
    image_class = None
    for label_index, label in enumerate(labels):
        if label in LABEL_SUBSET.keys():
            index = label_index
            image_class = LABEL_SUBSET[label]
            break

    # Save the image
    path_to_image = os.path.join(split_directory, image_class, str(example["image/id"].numpy()) + ".jpeg")
    tf.keras.preprocessing.image.save_img(path_to_image, example["image"])

    # Find the corresponding bounding box
    bounds = example["objects"]["bbox"][index].numpy()

    # Crop the image using the bounding box
    img = Image.open(path_to_image)
    height = img.height
    width = img.width

    # Tensorflow stores the bounds as [y0, x0, y1, x1]
    # PIL expects the bounds to be [x0, y0, x1, y1]
    bounds[0], bounds[1] = bounds[1], bounds[0]
    bounds[2], bounds[3] = bounds[3], bounds[2]

    # Convert the bounds from a fraction of the image size to a pixel value
    bounds[0] *= width
    bounds[1] *= height
    bounds[2] *= width
    bounds[3] *= height

    # Crop the image
    img = img.crop(bounds)

    # Save the image to the class directory within the split directory
    img.save(path_to_image)

def create_directories(split_name):
    '''
    Creates a directory to hold the split and a directory in it to hold each class

    Returns the path to the split directory

    Params:
        split_name: the name of the split to create a directory for
    '''
    def ensure_directory_exists(path):
        if not os.path.exists(path):
            os.makedirs(path)

    ensure_directory_exists(ROOT_DIR + split_name)

    for _, label in LABEL_SUBSET.items():
        ensure_directory_exists(ROOT_DIR + split_name + "/" + label)

    return ROOT_DIR + split_name

preprocess_data(ds_train, "train")
preprocess_data(ds_val, "validation")
preprocess_data(ds_test, "test")


from math import *
from scipy import optimize
from general import *

class P2C:
    def __init__(self, diam2, diamt, Cd, P1, Pi2, T1, T02, p0, pur1, pur2, R, GAMMA, output=False):
        self.output = output
        self.diam2 = diam2
        self.diamt = diamt
        self.At = pi * self.diamt ** 2 / 4
        self.A2 = pi * self.diam2 ** 2 / 4
        self.Cd = Cd
        self.P1 = P1
        self.Pi2 = Pi2
        self.Pt = P1  # placeholder
        self.Ps2 = Pi2  # placeholder
        self.Pr2 = Pi2  # placeholder
        self.T02 = T02
        self.T1 = T1
        self.p0 = p0
        self.R = R
        self.GAMMA = GAMMA
        self.X1 = P1**G17(self.GAMMA)
        self.Xt = self.X1 # a real value, P. 138
        self.Xi2 = Pi2**G17(self.GAMMA)
        self.Xr2 = 1  # placeholder
        self.Xs2 = 1  # placeholder
        self.T01 = self.T1/(self.X1**2)
        self.d02 = self.p0/(self.R*self.T02)
        self.d0t = self.d02  # from 2.17.3
        self.a02 = sqrt(self.GAMMA*self.R*self.T02)  # 2.17.4
        self.a0t = self.a02  # 2.17.4
        self.d01 = self.p0/(self.R*self.T01) #SHOULD BE T01??
        self.a01 = sqrt(self.GAMMA*self.R*self.T01) #SHOULD BE T01??
        self.dt = self.d0t*self.Xt**G5(self.GAMMA)  # placeholder
        self.Tt = (self.a02*self.X1)**2/(self.GAMMA*self.R)  # placeholder
        self.ct = 0  # placeholder
        self.M = 0  # placeholder
        self.Ts2 = self.T02

    def update(self):
        self.dt = self.d0t*self.Xt**G5(self.GAMMA)  # placeholder
        self.Tt = (self.a02*self.X1)**2/(self.GAMMA*self.R)  # placeholder
        self.Pr2 = self.Xr2**G7(self.GAMMA)
        self.Xs2 = (self.Xi2+self.Xr2-1)
        self.Ps2 = self.Xs2**G7(self.GAMMA)
        self.M = self.ct/(self.a01*self.Xt)
        self.Pt = self.Xt**G7(self.GAMMA)
        self.as2 = self.a02*self.Xs2
        self.Ts2 = (self.as2)**2/(self.GAMMA*self.R)
        self.d2s = (self.d02*self.Xs2**G5(self.GAMMA))
        self.c2s = G5(self.GAMMA)*self.a02*(self.Xi2-self.Xr2)
        self.mfr2 = self.A2*self.d2s*self.c2s
        self.M2 = self.c2s/(self.as2)
        self.M = self.ct/(self.a02*self.Xt)
        '''if self.M >= 1.0:
            self.M = 1.0
            self.Xt = self.X1*sqrt(G5(self.GAMMA)/(G5(self.GAMMA)+1))
            self.ct = self.a01*self.Xt'''

    def continuity(self):
        return self.d02*self.X1**G5(self.GAMMA)*self.Cd*self.At*self.ct-self.d02*(self.Xi2+self.Xr2-1)**G5(self.GAMMA)*self.A2*G5(self.GAMMA)*self.a02*(self.Xi2-self.Xr2)

    def thd(self):
        first = (G5(self.GAMMA)*(self.a02*(self.Xi2+self.Xr2-1))**2-G5(self.GAMMA)*(self.a02*self.X1)**2)
        second = ((G5(self.GAMMA)*self.a02*(self.Xi2-self.Xr2))**2-self.ct**2)
        return first+second

    def equations(self, params):
        self.Xr2, self.ct = params
        self.update()
        return self.continuity(), self.thd()

    def solve(self):
        print("P1: {:.3f}".format(self.P1))
        print("T02: {:.3f}".format(self.T02-273))
        print("dt: {:.3f}".format(self.diamt))
        print("d2: {:.3f}".format(self.diam2))
        print("Cd: {:.3f}".format(self.Cd))
        print("Pi2: {:.3f}".format(self.Pi2))

        print()
        array, infodict, msg, asd = optimize.fsolve(self.equations, (self.Xr2, self.ct), full_output=True)
        if self.output:
            print("Pr2: {:.3f}".format(self.Pr2))
            print("Ps2: {:.3f}".format(self.Ps2))
            print("Ts2: {:.1f}".format(self.Ts2-273))
            print("Pt: {:.2f}".format(self.Pt))
            print("Tt: {:.1f}".format(self.Tt-273))
            print("MFR: {:.1f}".format(self.mfr2*1000))
            print("Ct: {:.1f}".format(self.ct))
            print("Mt: {:.3f}".format(self.M))
            print("c2s: {:.1f}".format(self.c2s))
            print("Ms2: {:.3f}".format(self.M2))
            print("a01: {:.1f}".format(self.a02))

class C2P:
    def __init__(self, diam2, diamt, Cd, P1, Pi2, T1, p0, pur1, pur2, R, GAMMA, output=False):
        self.output = output
        self.diam2 = diam2
        self.diamt = diamt
        self.At = pi*self.diamt**2/4
        self.A2 = pi*self.diam2**2/4
        self.Cd = Cd
        self.P1 = P1
        self.Pi2 = Pi2
        self.Pt = P1  # placeholder
        self.Ps2 = Pi2  # placeholder
        self.Pr2 = Pi2  # placeholder
        self.T1 = T1
        self.p0 = p0
        self.R = R
        self.GAMMA = GAMMA
        self.Cp = (self.GAMMA*self.R)/(self.GAMMA-1)
        self.Cv = self.R/(self.GAMMA-1)
        self.pur1 = pur1
        self.pur2 = pur2

        self.X1 = self.P1**G17(self.GAMMA)
        self.Xi2 = self.Pi2**G17(self.GAMMA)
        self.Xr2 = 1  # placeholder
        self.Xs2 = 1  # placeholder
        self.Xt = self.Pt**G17(self.GAMMA)  # not a real value, see self.Pt
        self.T01 = self.T1/(self.X1**2)
        self.T02 = self.T01  # placeholder

        self.d01 = self.p0/(self.R*self.T01)
        self.d02 = self.d01  # placeholder
        self.d0t = self.d01  # from 2.16.1
        self.dt = self.d01*self.Xt**G5(self.GAMMA)

        self.a01 = sqrt(self.GAMMA*self.R*self.T01)  # from 2.16.2
        self.a0t = self.a01  # from 2.16.2
        self.Tt = (self.a01*self.Xt)**2/(self.GAMMA*self.R)
        self.a02 = self.a01  # placeholder
        self.as2 = self.a02  # placeholder
        self.Ts2 = self.T02  # placeholder
        self.ct = 0  # placeholder

    def update(self):
        self.M = self.ct/(self.a01*self.Xt)
        if self.M >= 1.0:
            self.M = 1.0
            self.Xt = self.X1*sqrt(G5(self.GAMMA)/(G5(self.GAMMA)+1))
            self.ct = self.a01*self.Xt
        self.T02 = (self.a02**2)/(self.GAMMA*self.R)
        self.dt = self.d01*self.Xt**G5(self.GAMMA)
        self.Tt = (self.a01*self.Xt)**2/(self.GAMMA*self.R)
        self.d02 = self.p0/(self.R*self.T02)
        self.Xs2 = self.Xi2+self.Xr2-1
        self.Ps2 = self.Xs2**G7(self.GAMMA)
        self.Pr2 = self.Xr2**G7(self.GAMMA)
        self.as2 = self.a02*self.Xs2
        self.Ts2 = (self.as2)**2/(self.GAMMA*self.R)
        self.Pt = self.Xt**G7(self.GAMMA)
        self.d2s = (self.d02*self.Xs2**G5(self.GAMMA))
        self.c2s = G5(self.GAMMA)*self.a02*(self.Xr2-self.Xi2)
        self.mfr2 = self.A2*self.d2s*self.c2s
        self.M2 = self.c2s/(self.as2)

        #for cyl to pipe conditions, object as mesh
        self.c = self.c2s
        self.a0 = self.a02
        self.d0 = self.d02
        self.T = self.Ts2
        self.Pur = self.pur2

    def continuity(self):
        return self.d01*self.Xt**G5(self.GAMMA)*self.Cd*self.At*-abs(self.ct) - self.d02*(self.Xi2+self.Xr2-1)**G5(self.GAMMA)*self.A2*G5(self.GAMMA)*self.a02*(self.Xi2-self.Xr2)

    def thd_1(self):
        return G5(self.GAMMA)*(self.a01*self.X1)**2-((G5(self.GAMMA)*self.a02*(self.Xi2-self.Xr2))**2+G5(self.GAMMA)*self.a02**2*(self.Xi2+self.Xr2-1)**2)

    def thd_2(self):
        return G5(self.GAMMA)*((self.a01*self.X1)**2-(self.a01*self.Xt)**2)-self.ct**2

    def momentum(self):
        return self.p0*(self.Xt**G7(self.GAMMA)-(self.Xi2+self.Xr2-1)**G7(self.GAMMA))+(self.d02*(self.Xi2+self.Xr2-1)**G5(self.GAMMA)*G5(self.GAMMA)*self.a02*(self.Xi2-self.Xr2))*(-abs(self.ct)-G5(self.GAMMA)*self.a02*(self.Xi2-self.Xr2))

    def equations(self, param):
        self.Xr2, self.Xt, self.a02, self.ct = param
        self.update()
        return self.continuity(), self.thd_1(), self.thd_2(), self.momentum()

    def mach_equations(self, param):
        self.Xr2, self.a02 = param
        self.update()
        return self.continuity(), self.thd_1()

    def solve(self):
        array, infodict, msg, asd = optimize.fsolve(self.equations, (self.Xr2, self.Xt, self.a02, self.ct), full_output=True)

        # dirty fix for sonic solution...
        if self.M == 1:
            array, infodict, msg, asd = optimize.fsolve(self.mach_equations, (self.X1, self.a01), full_output=True)
        if self.output:
            print("Pr2: {:.3f}".format(self.Pr2))
            print("Ps2: {:.3f}".format(self.Ps2))
            print("Ts2: {:.3f}".format(self.Ts2-273))
            print("Pt: {:.3f}".format(self.Xt ** G7(self.GAMMA)))
            print("Tt: {:.1f}".format(self.Tt-273))
            print("a02: {:.1f}".format(self.a02))
            print("ct: {:.1f}".format(self.ct))
            print("Mach @ port: {:.1f}".format(self.M))
            print()
            print("cs2: {:.2f}".format(self.c2s))
            print("Mfr2: {:.2f}".format(self.mfr2*1000))
            print("Mach2: {:.3f}".format(self.M2))

class P2P:
    def __init__(self, diam1, diam2, diamt, Cd, P1, P2, T0, T01, p0, R, GAMMA):
        self.diam1 = diam1
        self.diam2 = diam2
        self.diamt = diamt
        self.A1 = pi*diam1**2/4
        self.A2 = pi*diam2**2/4
        self.At = pi*diamt**2/4
        self.Ar = self.A2/self.A1 #area ratio, needed for Benson's constant pressure approximation theory
        self.Cd = Cd
        self.P1 = P1
        self.P2 = P2
        self.Pr1 = P1 #UNKNOWN placeholder, not a real value..
        self.Pr2 = P2 #UNKNOWN placeholder, not a real value..
        self.Pt = self.P1 #UNKNOWN placeholder, not a real value..
        self.R = R
        self.GAMMA = GAMMA
        self.T0 = T0
        self.T01 = T01
        self.T02 = self.T01 #UNKNOWN placeholder, not a real value...
        self.p0 = p0
        self.Xi1 = self.P1**G17(self.GAMMA)
        self.Xi2 = self.P2**G17(self.GAMMA)
        self.a0 = sqrt(self.GAMMA*self.R*self.T0)
        self.a01 = sqrt(self.GAMMA*self.R*self.T01)
        self.d01 = self.p0/(self.R*self.T01)
        self.d0t = self.d01  # from 2.12.1
        self.a0t = self.a01  # from 2.12.2

        #Unknowns
        self.Xr1 = ((1 - self.Ar) * self.Xi1 + 2 * self.Xi2 * self.Ar) / (1 + self.Ar) #Benson's constant p. approx. NOT A REAL VALUE //To be solved 1
        self.Xr2 = (2 * self.Xi1 - self.Xi2 * (1 - self.Ar)) / (1 + self.Ar) #Benson's constant p. approx. NOT A REAL VALUE //To be solved 2
        self.Xt = self.Pt**G17(self.GAMMA) # NOT A REAL VALUE, see self.Pt //To be solved 3
        self.a02 = self.a01 #placeholder, not a real value... //To be solved 4
        self.ct = 0 #placeholder, not a real value... //To be solved 5

        self.c1 = 0 #placeholder, not a real value...
        self.Tt = (self.a01*self.Xt)**2/(self.R*self.GAMMA) #placeholder, not a real value.. (see self.Xt)
        self.d02 = self.d01 #placeholder, not a real value... (see self.T02)
        self.dt = self.d01*self.Xt**G5(self.GAMMA) #placeholder, not a real value... (see self.Xt)
        self.mfr = self.dt*self.At*self.ct #mass flow rate
        self.mfr1 = self.d01*self.A1*self.c1

    def update(self):
        self.Tt = (self.a01*self.Xt)**2/(self.R*self.GAMMA)
        self.T02 = (self.a02)**2/(self.GAMMA*self.R) #solve T02 from 2.12.2
        self.d02 = self.p0/(self.R*self.T02) #from 2.12.1
        self.dt = self.d01*self.Xt**G5(self.GAMMA)
        self.Pt = self.Xt**G7(self.GAMMA) #Pressure ratio P from amplitude ratio X
        self.Pr1 = self.Xr1**G7(self.GAMMA)
        self.Pr2 = self.Xr2**G7(self.GAMMA)

        self.X1s = self.Xi1+self.Xr1-1
        self.X2s = self.Xi2+self.Xr2-1
        self.c1s = G5(self.GAMMA)*self.a01*(self.Xi1-self.Xr1)
        self.c2s = G5(self.GAMMA)*self.a02*(self.Xi2-self.Xr2)
        self.d1s = self.d01*self.X1s**G5(self.GAMMA)
        self.d2s = self.d02*self.X2s**G5(self.GAMMA)
        self.a1s = self.a01*self.X1s
        self.a2s = self.a02*self.X2s
        self.at = self.a0t*self.Xt
        self.mfr1 = self.d1s*self.A1*self.c1s
        self.mfr2 = self.d2s*self.A2*self.c2s
        self.mfrt = self.d01*self.At*self.ct

        self.M1 = self.c1s/self.a1s
        self.M2 = abs(self.c2s)/self.a2s
        self.Mt = self.ct/self.at

    #Theory 2.10
    def continuity_eq_2107(self):
        first = (self.d01*(self.Xi1+self.Xr1-1)**G5(self.GAMMA)*self.A1*G5(self.GAMMA)*self.a01*(self.Xi1-self.Xr1))
        second = (self.d02*(self.Xi2+self.Xr2-1)**G5(self.GAMMA)*self.A2*G5(self.GAMMA)*self.a02*(self.Xi2-self.Xr2))
        return first+second
    def first_law_of_thd_2108(self):
        first = ((G5(self.GAMMA)*self.a01*(self.Xi1-self.Xr1))**2+G5(self.GAMMA)*self.a01**2*(self.Xi1+self.Xr1-1)**2)
        second = ((G5(self.GAMMA)*self.a02*(self.Xi2-self.Xr2))**2+G5(self.GAMMA)*self.a02**2*(self.Xi2+self.Xr2-1)**2)
        return first-second
    def momentum_eq_2109(self):
        first= (self.p0*self.A2*((self.Xi1+self.Xr1-1)**G7(self.GAMMA)-(self.Xi2+self.Xr2-1)**G7(self.GAMMA)))
        second = (self.d01*(self.Xi1+self.Xr1-1)**G5(self.GAMMA)*self.A1*G5(self.GAMMA)*self.a01*(self.Xi1-self.Xr1))
        third = (G5(self.GAMMA)*self.a01*(self.Xi1-self.Xr1)+G5(self.GAMMA)*self.a02*(self.Xi2-self.Xr2))
        return first+second*third

    #Theory 2.11
    def continuity_eq_2117(self):
        return (self.Xi1+self.Xr1-1)**G5(self.GAMMA)*self.A1*(self.Xi1-self.Xr1)+(self.Xi2+self.Xr2-1)**G5(self.GAMMA)*self.A2*(self.Xi2-self.Xr2)
    def first_law_of_thd_2118(self):
        first = (G5(self.GAMMA)*(self.Xi1-self.Xr1)**2+G5(self.GAMMA)*(self.Xi1+self.Xr1-1)**2)
        second = (G5(self.GAMMA)*(self.Xi2-self.Xr2)**2+G5(self.GAMMA)*(self.Xi2+self.Xr2-1)**2)
        return first-second
    def momentum_eq_2109(self):
        first= (self.p0*self.A2*((self.Xi1+self.Xr1-1)**G7(self.GAMMA)-(self.Xi2+self.Xr2-1)**G7(self.GAMMA)))
        second = (self.d01*(self.Xi1+self.Xr1-1)**G5(self.GAMMA)*self.A1*G5(self.GAMMA)*self.a01*(self.Xi1-self.Xr1))
        third = (G5(self.GAMMA)*self.a01*(self.Xi1-self.Xr1)+G5(self.GAMMA)*self.a02*(self.Xi2-self.Xr2))
        return first+second*third

    #Theory 2.12
    def continuity_eq_2128(self):
        first = self.d01*(self.Xi1+self.Xr1-1)**G5(self.GAMMA)*self.A1*self.a01*(self.Xi1-self.Xr1)
        second = self.d02*(self.Xi2+self.Xr2-1)**G5(self.GAMMA)*self.A2*self.a02*(self.Xi2-self.Xr2)
        return first+second
    def continuity_eq_2129(self):
        return (self.Xi1+self.Xr1-1)**G5(self.GAMMA)*self.A1*self.a01*(self.Xi1-self.Xr1)-self.Xt**G5(self.GAMMA)*self.Cd*self.At*self.ct
    def first_law_of_thd_21210(self):
        first = ((G5(self.GAMMA)*self.a01*(self.Xi1-self.Xr1))**2+G5(self.GAMMA)*self.a01**2*(self.Xi1+self.Xr1-1)**2)
        second = ((G5(self.GAMMA)*self.a02*(self.Xi2-self.Xr2))**2+G5(self.GAMMA)*self.a02**2*(self.Xi2+self.Xr2-1)**2)
        return first-second
    def first_law_of_thd_21211(self):
        return G5(self.GAMMA)*((self.a01*(self.Xi1+self.Xr1-1))**2-(self.a01*self.Xt)**2)+(G5(self.GAMMA)*self.a01*(self.Xi1-self.Xr1))**2-self.ct**2
    def momentum_eq_21212(self):
        first = self.p0*self.A2*(self.Xt**G7(self.GAMMA)-(self.Xi2+self.Xr2-1)**G7(self.GAMMA))
        second = (self.d01*(self.Xi1+self.Xr1-1)**G5(self.GAMMA)*self.A1*G5(self.GAMMA)*self.a01*(self.Xi1-self.Xr1))*(self.ct+G5(self.GAMMA)*self.a01*(self.Xi2-self.Xr2))
        return first+second

    def continuity_1(self):
        #m1 - m2 = 0
        m1 = self.d01*self.X1s**G5(self.GAMMA)*self.A1*G5(self.GAMMA)*self.a01*(self.Xi1-self.Xr1)
        m2 = self.d02*self.X2s**G5(self.GAMMA)*self.A2*G5(self.GAMMA)*self.a02*(self.Xi2-self.Xr2)
        return m1+m2
    def continuity_2(self):
        #m1-mt = 0
        m1 = self.d01*self.X1s**G5(self.GAMMA)*self.A1*G5(self.GAMMA)*self.a01*(self.Xi1-self.Xr1)
        mt = self.Cd**2*self.dt*self.At*self.ct
        return m1-mt
    def thd_1(self):
        return (self.c1s**2+G5(self.GAMMA)*self.a1s**2)-(self.c2s**2+G5(self.GAMMA)*self.a2s**2)
    def thd_2(self):
        return (self.c1s**2+G5(self.GAMMA)*self.a1s**2)-(self.ct**2+G5(self.GAMMA)*self.at**2)
    def momentum(self):
        return self.A2*(self.Pt*self.p0-self.X2s**G7(self.GAMMA)*self.p0)+self.d01*self.X1s**G5(self.GAMMA)*self.A1*G5(self.GAMMA)*self.a01*(self.Xi1-self.Xr1)*(self.ct-self.c2s)

    def theory10(self, param):
        self.Xr1, self.Xr2, self.a02 = param
        self.update() #new values for d02, dt, T02 etc...
        if self.M1 > 1:
            self.M1 = 1
            self.Xr1 = (1+G4(self.GAMMA)*self.Xi1)/G6(self.GAMMA)
        return self.continuity_eq_2107(), self.first_law_of_thd_2108(), self.momentum_eq_2109()
    def theory11(self, param):
        self.Xr1, self.Xr2 = param
        self.update() #new values for d02, dt, T02 etc...
        if self.M2 > 1:
            self.M2 = 1
            self.Xr2 = (1+G4(self.GAMMA)*self.Xi2)/G6(self.GAMMA)
        return self.continuity_eq_2117(), self.first_law_of_thd_2118()
    def theory12(self, param):
        self.Xr1, self.Xr2, self.Xt, self.ct, self.a02 = param
        self.update() #new values for d02, dt, T02 etc...
        if self.Mt > 1:
            self.Mt = 1
            self.ct = self.a01*self.Xt
        return self.continuity_1(), self.continuity_2(), self.thd_1(), self.thd_2(), self.momentum_eq_21212()

    def solve(self):
        '''
        if self.A1<self.A2 and self.Cd == 1.0:
            print("T10")
            print()
            array  = optimize.fsolve(self.theory10, (self.Xr1, self.Xr2, self.a01))
        elif self.A1>self.A2 and self.Cd == 1.0:
            print("T11")
            print()
            array = optimize.fsolve(self.theory11, (self.Xr1, self.Xr2))
        else:
            print("T12")
            print()
            array  = optimize.fsolve(self.theory12, (self.Xr1, self.Xr2, self.Xr1, 0, self.a01))
        '''

        array, infodict, msg, asd = optimize.fsolve(self.theory12, (self.Xr1, self.Xr2, self.Xr1, 0, self.a01), full_output=True)

        print("Pr1: {:.4f}".format(self.Pr1))
        print("Pr2: {:.4f}".format(self.Pr2))
        print("T02: {:.1f}".format(self.T02))
        print("MFR1: {:.2f}".format(self.mfr1*1000))
        print("MFRt: {:.2f}".format(self.mfrt*1000))
        print("MFR2: {:.2f}".format(self.mfr2*1000))
        print()
        print("M1: {:.2f}".format(self.M1))
        print("M2: {:.2f}".format(self.M2))
        print("Mt: {:.2f}".format(self.Mt))
        print()
        for val in infodict['fvec']:
            print(val)
        return array

class M2M:
    def __init__(self, T0a, T0b, GAMMAa, GAMMAb, Ra, Rb, X1, X2):
        self.T0a = T0a
        self.T0b = T0b
        self.GAMMAa = GAMMAa
        self.GAMMAb = GAMMAb
        self.Ra = Ra
        self.Rb = Rb
        self.a0a = sqrt(self.GAMMAa*self.Ra*self.T0a)
        self.a0b = sqrt(self.GAMMAb*self.Rb*self.T0b)
        self.X1 = X1
        self.X2 = X2
        self.X1r = 1  # placeholder
        self.X2r = 1  # placeholder

    def momentum(self):
        return (self.a0a*G5(self.GAMMAa))/(self.a0b*G5(self.GAMMAb))*(self.X1-self.X2r)-(self.X1r-self.X2)

    def continuity(self):
        return (self.X1+self.X2r-1)**G7(self.GAMMAa)-(self.X1r+self.X2-1)**G7(self.GAMMAb)

    def equations(self, param):
        self.X1r, self.X2r = param
        return self.continuity(), self.momentum()

    def solve(self):
        array, infodict, msg, asd = optimize.fsolve(self.equations, (1, 1), full_output=True)
        return array


import xlrd

class Excel:
    def __init__(self, file_path='trip.xlsx'):
        self.path = file_path
        self.DAYS_COL = 0
        self.DETAILED_ROUTE_COL = 3
        self.TRANSPORTATION_COL = 4
        self.DISTANCE_COL = 5
        self.DURATION_COL = 6
        self.POIS_COL = 7
        self.COUNTRY_ROW = 0
        self.COUNTRY_COL = 1
        self.TRIP_START_ROW = 5
        self.wb = xlrd.open_workbook(self.path)
        self.sheet = self.wb.sheet_by_index(0)
        self.MAX_JUMP = 20  # when locate last col, only check up to next 20 rows
        self.STARTING_ROW = 5
        self.LAST_ROW = self.locate_last_row()

    def get_main_country(self):
        main_country = self.sheet.cell_value(self.COUNTRY_ROW, self.COUNTRY_COL)
        return main_country

    def locate_day(self, day_str):
        col = self.DAYS_COL
        row_runner = self.STARTING_ROW
        cell_val = self.sheet.cell_value(row_runner, col)
        while cell_val != day_str and row_runner < self.LAST_ROW:
            row_runner += 1
            cell_val = self.sheet.cell_value(row_runner, col)
        if row_runner == self.LAST_ROW and day_str != self.sheet.cell_value(self.LAST_ROW, col):
            # print("the trip goes to", self.sheet.cell_value(self.LAST_ROW, col))
            return -1
        # print(day_str + ": row ", row_runner)
        return row_runner

    def locate_last_row(self):
        col = self.DAYS_COL
        last_row_found = False
        row_runner = self.STARTING_ROW
        try:
            while not last_row_found:
                has_values = [(self.sheet.cell_value(row, col) != '')
                              for row in range(row_runner, row_runner+self.MAX_JUMP)]
                # print(has_values)
                if True in has_values:
                    row_runner += next(i for i in reversed(range(len(has_values))) if has_values[i] is True)
                    # print(row_runner)
                else:
                    # print("last row: ", row_runner)
                    return row_runner
        except IndexError:
            # print("last row: row", row_runner)
            return row_runner

    def get_daily_trip(self, day_str):
        day_start_row = self.locate_day(day_str)
        next_day_start_row = self.locate_day(day_str[:-1]+str(int(day_str[-1])+1))
        col = self.DETAILED_ROUTE_COL
        row_runner = day_start_row
        if row_runner == self.LAST_ROW:
            # print("last day: go home")
            return
        cell_runner = self.sheet.cell(row_runner, col)
        daily_trip = []
        while row_runner < next_day_start_row:
            if cell_runner.value is not '':
                daily_trip.append(cell_runner.value)
            row_runner += 1
            cell_runner = self.sheet.cell(row_runner, col)
        # print(routes)
        return daily_trip


from django.shortcuts import render,redirect
from .models import cutoff
# Create your views here.
def home(request):
    colleges = cutoff.objects.all().order_by('-open_percentile')
    context = {'colleges' : colleges}
    return render(request,'home.html',context=context)

def start(request):
    colleges = cutoff.objects.all().order_by('-open_percentile')
    context = {'colleges' : colleges}
    return render(request,'start.html',context=context) #replace 'testing.html' with 'start.html'

def search_colleges(request):
    item_searched = 0
    percentile_entered_float=0
    colleges = cutoff.objects.all().order_by('-open_percentile')
    if request.method == 'POST':
        item_searched = request.POST['search']
        percentile_entered = request.POST['percentile_entered']
        percentile_entered_float=0
        if (percentile_entered):
            percentile_entered_float = float(percentile_entered)
        if item_searched:
            colleges = cutoff.objects.filter(college_name__contains=item_searched).order_by('-open_percentile')
        elif (not percentile_entered) & (not item_searched):
            colleges = cutoff.objects.all().order_by('-open_percentile')
            context = {'colleges' : colleges}
            return render(request,'home.html',context=context)

    context = {'colleges' : colleges, 'item_searched': item_searched, 'percentile_entered_float':percentile_entered_float}
    return render(request,'search_colleges.html',context=context)


from data import puzzle

testInput = """$ cd /
$ ls
dir a
14848514 b.txt
8504156 c.dat
dir d
$ cd a
$ ls
dir e
29116 f
2557 g
62596 h.lst
$ cd e
$ ls
584 i
$ cd ..
$ cd ..
$ cd d
$ ls
4060174 j
8033020 d.log
5626152 d.ext
7214296 k"""

def findDirUnder100k(log: str) -> int:
    splitLog = log.split("\n")
    directories = {}
    Pwd = []
    for line in splitLog:
        splitLine = line.split(" ")
        if line.startswith("$ cd"):
            directory = splitLine[2]
            if directory == "..":
                Pwd.pop() # remove the last thing appended to the current dir
            else:
                Pwd.append(directory)
                if str(Pwd) not in directories:
                    directories[str(Pwd)] = 0
        if splitLine[0].isdigit():
            # create new list, append one directory at a time,
            # update sizes of directories in dictionary
            tempList = []
            for directory in Pwd:
                tempList.append(directory)
                directories[str(tempList)] += int(splitLine[0])
    directoryTotals = list(directories.values())
    sumUnder100k = 0
    for value in directoryTotals:
        if value <= 100000:
            sumUnder100k += value
    return sumUnder100k

def findDirToDelete(log: str) -> int:
    splitLog = log.split("\n")
    directories = {}
    Pwd = []
    for line in splitLog:
        splitLine = line.split(" ")
        if line.startswith("$ cd"):
            directory = splitLine[2]
            if directory == "..":
                Pwd.pop() # remove the last thing appended to the current dir
            else:
                Pwd.append(directory)
                if str(Pwd) not in directories:
                    directories[str(Pwd)] = 0
        if splitLine[0].isdigit():
            # create new list, append one directory at a time,
            # update sizes of directories in dictionary
            tempList = []
            for directory in Pwd:
                tempList.append(directory)
                directories[str(tempList)] += int(splitLine[0])

    directoryTotals = list(directories.values())

    TOTAL_STORAGE_AVAILABLE = 70000000
    SPACE_REQUIRED_FOR_UPDATE = 30000000
    totalSpaceUsed = directories["['/']"]
    unusedSpace = TOTAL_STORAGE_AVAILABLE - totalSpaceUsed
    spaceNeeded = SPACE_REQUIRED_FOR_UPDATE - unusedSpace
    print(f'total space used: {totalSpaceUsed}; space available {unusedSpace}\nspace needed for update: {spaceNeeded}')
    currentDelDirSize = TOTAL_STORAGE_AVAILABLE
    for value in directoryTotals:
        if value >= spaceNeeded and value < currentDelDirSize:
            currentDelDirSize = value
    return currentDelDirSize

# print(findDirUnder100k(testInput))
print(findDirToDelete(puzzle))